forked from iluwatar/java-design-patterns
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
task: Add Composite Entity pattern (iluwatar#1705)
* add composite entity pattern * add composite entity pattern * Update ReactorTest.java * resolve some code quality problems * modified a lot * remove some extra codes * modified README * removed the author name and adjusted the spacing Co-authored-by: zwebrain <[email protected]> Co-authored-by: Subhrodip Mohanta <[email protected]>
- Loading branch information
1 parent
2fce2e4
commit 09b577f
Showing
14 changed files
with
406 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
--- | ||
layout: pattern | ||
title: Composite Entity | ||
folder: composite-entity | ||
permalink: /patterns/composite-entity/ | ||
categories: Structural | ||
tags: | ||
- Enterprise Integration Pattern | ||
--- | ||
|
||
## Intent | ||
|
||
It is used to model, represent, and manage a set of persistent objects that are interrelated, rather than representing them as individual fine-grained entities. | ||
|
||
## Explanation | ||
|
||
Real world example | ||
|
||
> For a console, there may be many interfaces that need to be managed and controlled. Using the composite entity pattern, dependent objects such as messages and signals can be combined together and controlled using a single object. | ||
In plain words | ||
|
||
> Composite entity pattern allows a set of related objects to be represented and managed by a unified object. | ||
**Programmatic Example** | ||
|
||
We need a generic solution for the problem. To achieve this, let's introduce a generic | ||
Composite Entity Pattern. | ||
|
||
```java | ||
public abstract class DependentObject<T> { | ||
|
||
T data; | ||
|
||
public void setData(T message) { | ||
this.data = message; | ||
} | ||
|
||
public T getData() { | ||
return data; | ||
} | ||
} | ||
|
||
public abstract class CoarseGrainedObject<T> { | ||
|
||
DependentObject<T>[] dependentObjects; | ||
|
||
public void setData(T... data) { | ||
IntStream.range(0, data.length).forEach(i -> dependentObjects[i].setData(data[i])); | ||
} | ||
|
||
public T[] getData() { | ||
return (T[]) Arrays.stream(dependentObjects).map(DependentObject::getData).toArray(); | ||
} | ||
} | ||
|
||
``` | ||
|
||
The specialized composite entity `console` inherit from this base class as follows. | ||
|
||
```java | ||
public class MessageDependentObject extends DependentObject<String> { | ||
|
||
} | ||
|
||
public class SignalDependentObject extends DependentObject<String> { | ||
|
||
} | ||
|
||
public class ConsoleCoarseGrainedObject extends CoarseGrainedObject<String> { | ||
|
||
@Override | ||
public String[] getData() { | ||
super.getData(); | ||
return new String[]{ | ||
dependentObjects[0].getData(), dependentObjects[1].getData() | ||
}; | ||
} | ||
|
||
public void init() { | ||
dependentObjects = new DependentObject[]{ | ||
new MessageDependentObject(), new SignalDependentObject()}; | ||
} | ||
} | ||
|
||
public class CompositeEntity { | ||
|
||
private final ConsoleCoarseGrainedObject console = new ConsoleCoarseGrainedObject(); | ||
|
||
public void setData(String message, String signal) { | ||
console.setData(message, signal); | ||
} | ||
|
||
public String[] getData() { | ||
return console.getData(); | ||
} | ||
} | ||
``` | ||
|
||
Now managing the assignment of message and signal objects with the composite entity `console`. | ||
|
||
```java | ||
var console = new CompositeEntity(); | ||
console.init(); | ||
console.setData("No Danger", "Green Light"); | ||
Arrays.stream(console.getData()).forEach(LOGGER::info); | ||
console.setData("Danger", "Red Light"); | ||
Arrays.stream(console.getData()).forEach(LOGGER::info); | ||
``` | ||
|
||
## Class diagram | ||
|
||
 | ||
|
||
## Applicability | ||
|
||
Use the Composite Entity Pattern in the following situation: | ||
|
||
* You want to manage multiple dependency objects through one object to adjust the degree of granularity between objects. At the same time, the lifetime of dependency objects depends on a coarse-grained object. | ||
## Credits | ||
|
||
* [Composite Entity Pattern in wikipedia](https://en.wikipedia.org/wiki/Composite_entity_pattern) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
@startuml | ||
package com.iluwatar.compositeentity { | ||
class App { | ||
+ App(message: String, signal: String) | ||
+ main(args : String[]) {static} | ||
} | ||
class CompositeEntity{ | ||
- console : ConsoleCoarseGrainedObject | ||
+ CompositeEntity() | ||
+ setData(message: String, signal: String) | ||
+ getData() | ||
+ init() | ||
} | ||
abstract CoarseGrainedObject{ | ||
- dependentObjects : DependentObject[] | ||
+ CoarseGrainedObject() | ||
+ setData(data: T[]) | ||
+ getData() | ||
} | ||
abstract DependentObject{ | ||
- data : T | ||
+ DependentObject() | ||
+ setData(data: T) | ||
+ getData() | ||
} | ||
class ConsoleCoarseGrainedObject{ | ||
+ ConsoleCoarseGrainedObject() | ||
+ getData() | ||
+ init() | ||
} | ||
class MessageDependentObject{ | ||
+ MessageDependentObject() | ||
} | ||
class SignalDependentObject{ | ||
+ SignalDependentObject() | ||
} | ||
|
||
MessageDependentObject --|> DependentObject | ||
SignalDependentObject --|> DependentObject | ||
ConsoleCoarseGrainedObject --|> CoarseGrainedObject | ||
CompositeEntity -right-> ConsoleCoarseGrainedObject | ||
CoarseGrainedObject "1" o--> "0.." DependentObject | ||
App .right.> CompositeEntity | ||
} | ||
@enduml |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<parent> | ||
<artifactId>java-design-patterns</artifactId> | ||
<groupId>com.iluwatar</groupId> | ||
<version>1.25.0-SNAPSHOT</version> | ||
</parent> | ||
<modelVersion>4.0.0</modelVersion> | ||
<artifactId>composite-entity</artifactId> | ||
<dependencies> | ||
<dependency> | ||
<groupId>org.junit.jupiter</groupId> | ||
<artifactId>junit-jupiter-engine</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-assembly-plugin</artifactId> | ||
<executions> | ||
<execution> | ||
<configuration> | ||
<archive> | ||
<manifest> | ||
<mainClass>com.iluwatar.composite-entity.com.iluwatar.compositeentity.App</mainClass> | ||
</manifest> | ||
</archive> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
</project> |
38 changes: 38 additions & 0 deletions
38
composite-entity/src/main/java/com/iluwatar/compositeentity/App.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package com.iluwatar.compositeentity; | ||
|
||
import java.util.Arrays; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
|
||
/** | ||
* Composite entity is a Java EE Software design pattern and it is used to model, represent, and | ||
* manage a set of interrelated persistent objects rather than representing them as individual | ||
* fine-grained entity beans, and also a composite entity bean represents a graph of objects. | ||
*/ | ||
@Slf4j | ||
public class App { | ||
|
||
|
||
/** | ||
* An instance that a console manages two related objects. | ||
*/ | ||
public App(String message, String signal) { | ||
var console = new CompositeEntity(); | ||
console.init(); | ||
console.setData(message, signal); | ||
Arrays.stream(console.getData()).forEach(LOGGER::info); | ||
console.setData("Danger", "Red Light"); | ||
Arrays.stream(console.getData()).forEach(LOGGER::info); | ||
} | ||
|
||
/** | ||
* Program entry point. | ||
* | ||
* @param args command line args | ||
*/ | ||
public static void main(String[] args) { | ||
|
||
new App("No Danger", "Green Light"); | ||
|
||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
composite-entity/src/main/java/com/iluwatar/compositeentity/CoarseGrainedObject.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.iluwatar.compositeentity; | ||
|
||
import java.util.Arrays; | ||
import java.util.stream.IntStream; | ||
|
||
/** | ||
* A coarse-grained object is an object with its own life cycle manages its own relationships to | ||
* other objects. It can be an object contained in the composite entity, or, composite entity itself | ||
* can be the coarse-grained object which holds dependent objects. | ||
*/ | ||
|
||
public abstract class CoarseGrainedObject<T> { | ||
|
||
DependentObject<T>[] dependentObjects; | ||
|
||
public void setData(T... data) { | ||
IntStream.range(0, data.length).forEach(i -> dependentObjects[i].setData(data[i])); | ||
} | ||
|
||
public T[] getData() { | ||
return (T[]) Arrays.stream(dependentObjects).map(DependentObject::getData).toArray(); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
composite-entity/src/main/java/com/iluwatar/compositeentity/CompositeEntity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.iluwatar.compositeentity; | ||
|
||
/** | ||
* Composite entity is the coarse-grained entity bean which may be the coarse-grained object, or may | ||
* contain a reference to the coarse-grained object. | ||
*/ | ||
|
||
public class CompositeEntity { | ||
|
||
private final ConsoleCoarseGrainedObject console = new ConsoleCoarseGrainedObject(); | ||
|
||
public void setData(String message, String signal) { | ||
console.setData(message, signal); | ||
} | ||
|
||
public String[] getData() { | ||
return console.getData(); | ||
} | ||
|
||
public void init() { | ||
console.init(); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
composite-entity/src/main/java/com/iluwatar/compositeentity/ConsoleCoarseGrainedObject.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.iluwatar.compositeentity; | ||
|
||
/** | ||
* A specific CoarseGrainedObject to implement a console. | ||
*/ | ||
|
||
public class ConsoleCoarseGrainedObject extends CoarseGrainedObject<String> { | ||
|
||
@Override | ||
public String[] getData() { | ||
return new String[]{ | ||
dependentObjects[0].getData(), dependentObjects[1].getData() | ||
}; | ||
} | ||
|
||
public void init() { | ||
dependentObjects = new DependentObject[]{ | ||
new MessageDependentObject(), new SignalDependentObject()}; | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
composite-entity/src/main/java/com/iluwatar/compositeentity/DependentObject.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.iluwatar.compositeentity; | ||
|
||
/** | ||
* It is an object, which can contain other dependent objects (there may be a tree of objects within | ||
* the composite entity), that depends on the coarse-grained object and has its life cycle managed | ||
* by the coarse-grained object. | ||
*/ | ||
|
||
public abstract class DependentObject<T> { | ||
|
||
T data; | ||
|
||
public void setData(T message) { | ||
this.data = message; | ||
} | ||
|
||
public T getData() { | ||
return data; | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
composite-entity/src/main/java/com/iluwatar/compositeentity/MessageDependentObject.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.iluwatar.compositeentity; | ||
|
||
/** | ||
* The first DependentObject to show message. | ||
*/ | ||
|
||
public class MessageDependentObject extends DependentObject<String> { | ||
|
||
} |
9 changes: 9 additions & 0 deletions
9
composite-entity/src/main/java/com/iluwatar/compositeentity/SignalDependentObject.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.iluwatar.compositeentity; | ||
|
||
/** | ||
* The second DependentObject to show message. | ||
*/ | ||
|
||
public class SignalDependentObject extends DependentObject<String> { | ||
|
||
} |
25 changes: 25 additions & 0 deletions
25
composite-entity/src/test/java/com/iluwatar/compositeentity/AppTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.iluwatar.compositeentity; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
/** | ||
* com.iluwatar.compositeentity.App running test | ||
*/ | ||
class AppTest { | ||
|
||
/** | ||
* Issue: Add at least one assertion to this test case. | ||
* <p> | ||
* Solution: Inserted assertion to check whether the execution of the main method in {@link | ||
* App#main(String[])} throws an exception. | ||
*/ | ||
|
||
@Test | ||
void shouldExecuteApplicationWithoutException() { | ||
|
||
assertDoesNotThrow(() -> App.main(new String[]{})); | ||
|
||
} | ||
} |
Oops, something went wrong.