Skip to content

Commit 09b577f

Browse files
zwebrainohbus
andauthored
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 <11811721@mail.sustech.edu.cn> Co-authored-by: Subhrodip Mohanta <hello@subho.xyz>
1 parent 2fce2e4 commit 09b577f

14 files changed

+406
-0
lines changed

composite-entity/README.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
---
2+
layout: pattern
3+
title: Composite Entity
4+
folder: composite-entity
5+
permalink: /patterns/composite-entity/
6+
categories: Structural
7+
tags:
8+
- Enterprise Integration Pattern
9+
---
10+
11+
## Intent
12+
13+
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.
14+
15+
## Explanation
16+
17+
Real world example
18+
19+
> 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.
20+
21+
In plain words
22+
23+
> Composite entity pattern allows a set of related objects to be represented and managed by a unified object.
24+
25+
**Programmatic Example**
26+
27+
We need a generic solution for the problem. To achieve this, let's introduce a generic
28+
Composite Entity Pattern.
29+
30+
```java
31+
public abstract class DependentObject<T> {
32+
33+
T data;
34+
35+
public void setData(T message) {
36+
this.data = message;
37+
}
38+
39+
public T getData() {
40+
return data;
41+
}
42+
}
43+
44+
public abstract class CoarseGrainedObject<T> {
45+
46+
DependentObject<T>[] dependentObjects;
47+
48+
public void setData(T... data) {
49+
IntStream.range(0, data.length).forEach(i -> dependentObjects[i].setData(data[i]));
50+
}
51+
52+
public T[] getData() {
53+
return (T[]) Arrays.stream(dependentObjects).map(DependentObject::getData).toArray();
54+
}
55+
}
56+
57+
```
58+
59+
The specialized composite entity `console` inherit from this base class as follows.
60+
61+
```java
62+
public class MessageDependentObject extends DependentObject<String> {
63+
64+
}
65+
66+
public class SignalDependentObject extends DependentObject<String> {
67+
68+
}
69+
70+
public class ConsoleCoarseGrainedObject extends CoarseGrainedObject<String> {
71+
72+
@Override
73+
public String[] getData() {
74+
super.getData();
75+
return new String[]{
76+
dependentObjects[0].getData(), dependentObjects[1].getData()
77+
};
78+
}
79+
80+
public void init() {
81+
dependentObjects = new DependentObject[]{
82+
new MessageDependentObject(), new SignalDependentObject()};
83+
}
84+
}
85+
86+
public class CompositeEntity {
87+
88+
private final ConsoleCoarseGrainedObject console = new ConsoleCoarseGrainedObject();
89+
90+
public void setData(String message, String signal) {
91+
console.setData(message, signal);
92+
}
93+
94+
public String[] getData() {
95+
return console.getData();
96+
}
97+
}
98+
```
99+
100+
Now managing the assignment of message and signal objects with the composite entity `console`.
101+
102+
```java
103+
var console = new CompositeEntity();
104+
console.init();
105+
console.setData("No Danger", "Green Light");
106+
Arrays.stream(console.getData()).forEach(LOGGER::info);
107+
console.setData("Danger", "Red Light");
108+
Arrays.stream(console.getData()).forEach(LOGGER::info);
109+
```
110+
111+
## Class diagram
112+
113+
![alt text](./etc/composite_entity.urm.png "Composite Entity Pattern")
114+
115+
## Applicability
116+
117+
Use the Composite Entity Pattern in the following situation:
118+
119+
* 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.
120+
## Credits
121+
122+
* [Composite Entity Pattern in wikipedia](https://en.wikipedia.org/wiki/Composite_entity_pattern)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
@startuml
2+
package com.iluwatar.compositeentity {
3+
class App {
4+
+ App(message: String, signal: String)
5+
+ main(args : String[]) {static}
6+
}
7+
class CompositeEntity{
8+
- console : ConsoleCoarseGrainedObject
9+
+ CompositeEntity()
10+
+ setData(message: String, signal: String)
11+
+ getData()
12+
+ init()
13+
}
14+
abstract CoarseGrainedObject{
15+
- dependentObjects : DependentObject[]
16+
+ CoarseGrainedObject()
17+
+ setData(data: T[])
18+
+ getData()
19+
}
20+
abstract DependentObject{
21+
- data : T
22+
+ DependentObject()
23+
+ setData(data: T)
24+
+ getData()
25+
}
26+
class ConsoleCoarseGrainedObject{
27+
+ ConsoleCoarseGrainedObject()
28+
+ getData()
29+
+ init()
30+
}
31+
class MessageDependentObject{
32+
+ MessageDependentObject()
33+
}
34+
class SignalDependentObject{
35+
+ SignalDependentObject()
36+
}
37+
38+
MessageDependentObject --|> DependentObject
39+
SignalDependentObject --|> DependentObject
40+
ConsoleCoarseGrainedObject --|> CoarseGrainedObject
41+
CompositeEntity -right-> ConsoleCoarseGrainedObject
42+
CoarseGrainedObject "1" o--> "0.." DependentObject
43+
App .right.> CompositeEntity
44+
}
45+
@enduml
89.6 KB
Loading

composite-entity/pom.xml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>java-design-patterns</artifactId>
7+
<groupId>com.iluwatar</groupId>
8+
<version>1.25.0-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
<artifactId>composite-entity</artifactId>
12+
<dependencies>
13+
<dependency>
14+
<groupId>org.junit.jupiter</groupId>
15+
<artifactId>junit-jupiter-engine</artifactId>
16+
<scope>test</scope>
17+
</dependency>
18+
</dependencies>
19+
<build>
20+
<plugins>
21+
<plugin>
22+
<groupId>org.apache.maven.plugins</groupId>
23+
<artifactId>maven-assembly-plugin</artifactId>
24+
<executions>
25+
<execution>
26+
<configuration>
27+
<archive>
28+
<manifest>
29+
<mainClass>com.iluwatar.composite-entity.com.iluwatar.compositeentity.App</mainClass>
30+
</manifest>
31+
</archive>
32+
</configuration>
33+
</execution>
34+
</executions>
35+
</plugin>
36+
</plugins>
37+
</build>
38+
39+
</project>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.iluwatar.compositeentity;
2+
3+
import java.util.Arrays;
4+
import lombok.extern.slf4j.Slf4j;
5+
6+
7+
/**
8+
* Composite entity is a Java EE Software design pattern and it is used to model, represent, and
9+
* manage a set of interrelated persistent objects rather than representing them as individual
10+
* fine-grained entity beans, and also a composite entity bean represents a graph of objects.
11+
*/
12+
@Slf4j
13+
public class App {
14+
15+
16+
/**
17+
* An instance that a console manages two related objects.
18+
*/
19+
public App(String message, String signal) {
20+
var console = new CompositeEntity();
21+
console.init();
22+
console.setData(message, signal);
23+
Arrays.stream(console.getData()).forEach(LOGGER::info);
24+
console.setData("Danger", "Red Light");
25+
Arrays.stream(console.getData()).forEach(LOGGER::info);
26+
}
27+
28+
/**
29+
* Program entry point.
30+
*
31+
* @param args command line args
32+
*/
33+
public static void main(String[] args) {
34+
35+
new App("No Danger", "Green Light");
36+
37+
}
38+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.iluwatar.compositeentity;
2+
3+
import java.util.Arrays;
4+
import java.util.stream.IntStream;
5+
6+
/**
7+
* A coarse-grained object is an object with its own life cycle manages its own relationships to
8+
* other objects. It can be an object contained in the composite entity, or, composite entity itself
9+
* can be the coarse-grained object which holds dependent objects.
10+
*/
11+
12+
public abstract class CoarseGrainedObject<T> {
13+
14+
DependentObject<T>[] dependentObjects;
15+
16+
public void setData(T... data) {
17+
IntStream.range(0, data.length).forEach(i -> dependentObjects[i].setData(data[i]));
18+
}
19+
20+
public T[] getData() {
21+
return (T[]) Arrays.stream(dependentObjects).map(DependentObject::getData).toArray();
22+
}
23+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.iluwatar.compositeentity;
2+
3+
/**
4+
* Composite entity is the coarse-grained entity bean which may be the coarse-grained object, or may
5+
* contain a reference to the coarse-grained object.
6+
*/
7+
8+
public class CompositeEntity {
9+
10+
private final ConsoleCoarseGrainedObject console = new ConsoleCoarseGrainedObject();
11+
12+
public void setData(String message, String signal) {
13+
console.setData(message, signal);
14+
}
15+
16+
public String[] getData() {
17+
return console.getData();
18+
}
19+
20+
public void init() {
21+
console.init();
22+
}
23+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.iluwatar.compositeentity;
2+
3+
/**
4+
* A specific CoarseGrainedObject to implement a console.
5+
*/
6+
7+
public class ConsoleCoarseGrainedObject extends CoarseGrainedObject<String> {
8+
9+
@Override
10+
public String[] getData() {
11+
return new String[]{
12+
dependentObjects[0].getData(), dependentObjects[1].getData()
13+
};
14+
}
15+
16+
public void init() {
17+
dependentObjects = new DependentObject[]{
18+
new MessageDependentObject(), new SignalDependentObject()};
19+
}
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.iluwatar.compositeentity;
2+
3+
/**
4+
* It is an object, which can contain other dependent objects (there may be a tree of objects within
5+
* the composite entity), that depends on the coarse-grained object and has its life cycle managed
6+
* by the coarse-grained object.
7+
*/
8+
9+
public abstract class DependentObject<T> {
10+
11+
T data;
12+
13+
public void setData(T message) {
14+
this.data = message;
15+
}
16+
17+
public T getData() {
18+
return data;
19+
}
20+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.iluwatar.compositeentity;
2+
3+
/**
4+
* The first DependentObject to show message.
5+
*/
6+
7+
public class MessageDependentObject extends DependentObject<String> {
8+
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.iluwatar.compositeentity;
2+
3+
/**
4+
* The second DependentObject to show message.
5+
*/
6+
7+
public class SignalDependentObject extends DependentObject<String> {
8+
9+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.iluwatar.compositeentity;
2+
3+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
/**
8+
* com.iluwatar.compositeentity.App running test
9+
*/
10+
class AppTest {
11+
12+
/**
13+
* Issue: Add at least one assertion to this test case.
14+
* <p>
15+
* Solution: Inserted assertion to check whether the execution of the main method in {@link
16+
* App#main(String[])} throws an exception.
17+
*/
18+
19+
@Test
20+
void shouldExecuteApplicationWithoutException() {
21+
22+
assertDoesNotThrow(() -> App.main(new String[]{}));
23+
24+
}
25+
}

0 commit comments

Comments
 (0)