Skip to content

Commit

Permalink
task: Add Composite Entity pattern (#1705)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
3 people committed Apr 26, 2021
1 parent 2fce2e4 commit 09b577f
Show file tree
Hide file tree
Showing 14 changed files with 406 additions and 0 deletions.
122 changes: 122 additions & 0 deletions composite-entity/README.md
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

![alt text](./etc/composite_entity.urm.png "Composite Entity Pattern")

## 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)
45 changes: 45 additions & 0 deletions composite-entity/etc/composite-entity.urm.puml
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
Binary file added composite-entity/etc/composite_entity.urm.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 39 additions & 0 deletions composite-entity/pom.xml
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>
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");

}
}
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();
}
}
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();
}
}
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()};
}
}
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;
}
}
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> {

}
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> {

}
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[]{}));

}
}

0 comments on commit 09b577f

Please sign in to comment.