#590 Add explanation for Composite pattern

This commit is contained in:
Ilkka Seppälä
2017-08-31 22:11:58 +03:00
parent 7f1fac036e
commit f28ed7b46e
11 changed files with 117 additions and 139 deletions

View File

@ -16,7 +16,119 @@ Compose objects into tree structures to represent part-whole
hierarchies. Composite lets clients treat individual objects and compositions
of objects uniformly.
![alt text](./etc/composite_1.png "Composite")
## Explanation
Real world example
> Every sentence is composed of words which are in turn composed of characters. Each of these objects is printable and they can have something printed before or after them like sentence always ends with full stop and word always has space before it
In plain words
> Composite pattern lets clients treat the individual objects in a uniform manner.
Wikipedia says
> In software engineering, the composite pattern is a partitioning design pattern. The composite pattern describes that a group of objects is to be treated in the same way as a single instance of an object. The intent of a composite is to "compose" objects into tree structures to represent part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects and compositions uniformly.
**Programmatic Example**
Taking our sentence example from above. Here we have the base class and different printable types
```
public abstract class LetterComposite {
private List<LetterComposite> children = new ArrayList<>();
public void add(LetterComposite letter) {
children.add(letter);
}
public int count() {
return children.size();
}
protected void printThisBefore() {}
protected void printThisAfter() {}
public void print() {
printThisBefore();
for (LetterComposite letter : children) {
letter.print();
}
printThisAfter();
}
}
public class Letter extends LetterComposite {
private char c;
public Letter(char c) {
this.c = c;
}
@Override
protected void printThisBefore() {
System.out.print(c);
}
}
public class Word extends LetterComposite {
public Word(List<Letter> letters) {
for (Letter l : letters) {
this.add(l);
}
}
@Override
protected void printThisBefore() {
System.out.print(" ");
}
}
public class Sentence extends LetterComposite {
public Sentence(List<Word> words) {
for (Word w : words) {
this.add(w);
}
}
@Override
protected void printThisAfter() {
System.out.print(".");
}
}
```
Then we have a messenger to carry messages
```
public class Messenger {
LetterComposite messageFromOrcs() {
List<Word> words = new ArrayList<>();
words.add(new Word(Arrays.asList(new Letter('W'), new Letter('h'), new Letter('e'), new Letter('r'), new Letter('e'))));
words.add(new Word(Arrays.asList(new Letter('t'), new Letter('h'), new Letter('e'), new Letter('r'), new Letter('e'))));
words.add(new Word(Arrays.asList(new Letter('i'), new Letter('s'))));
words.add(new Word(Arrays.asList(new Letter('a'))));
words.add(new Word(Arrays.asList(new Letter('w'), new Letter('h'), new Letter('i'), new Letter('p'))));
words.add(new Word(Arrays.asList(new Letter('t'), new Letter('h'), new Letter('e'), new Letter('r'), new Letter('e'))));
words.add(new Word(Arrays.asList(new Letter('i'), new Letter('s'))));
words.add(new Word(Arrays.asList(new Letter('a'))));
words.add(new Word(Arrays.asList(new Letter('w'), new Letter('a'), new Letter('y'))));
return new Sentence(words);
}
LetterComposite messageFromElves() {
List<Word> words = new ArrayList<>();
words.add(new Word(Arrays.asList(new Letter('M'), new Letter('u'), new Letter('c'), new Letter('h'))));
words.add(new Word(Arrays.asList(new Letter('w'), new Letter('i'), new Letter('n'), new Letter('d'))));
words.add(new Word(Arrays.asList(new Letter('p'), new Letter('o'), new Letter('u'), new Letter('r'), new Letter('s'))));
words.add(new Word(Arrays.asList(new Letter('f'), new Letter('r'), new Letter('o'), new Letter('m'))));
words.add(new Word(Arrays.asList(new Letter('y'), new Letter('o'), new Letter('u'), new Letter('r'))));
words.add(new Word(Arrays.asList(new Letter('m'), new Letter('o'), new Letter('u'), new Letter('t'), new Letter('h'))));
return new Sentence(words);
}
}
```
And then it can be used as
```
LetterComposite orcMessage = new Messenger().messageFromOrcs();
orcMessage.print(); // Where there is a whip there is a way.
LetterComposite elfMessage = new Messenger().messageFromElves();
elfMessage.print(); // Much wind pours from your mouth.
```
## Applicability
Use the Composite pattern when

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,75 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
<class id="1" language="java" name="com.iluwatar.composite.Messenger" project="composite"
file="/composite/src/main/java/com/iluwatar/composite/Messenger.java" binary="false" corner="BOTTOM_RIGHT">
<position height="124" width="247" x="118" y="180"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="2" language="java" name="com.iluwatar.composite.Sentence" project="composite"
file="/composite/src/main/java/com/iluwatar/composite/Sentence.java" binary="false" corner="BOTTOM_RIGHT">
<position height="124" width="157" x="118" y="407"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="3" language="java" name="com.iluwatar.composite.LetterComposite" project="composite"
file="/composite/src/main/java/com/iluwatar/composite/LetterComposite.java" binary="false" corner="BOTTOM_RIGHT">
<position height="177" width="176" x="405" y="180"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="4" language="java" name="com.iluwatar.composite.Letter" project="composite"
file="/composite/src/main/java/com/iluwatar/composite/Letter.java" binary="false" corner="BOTTOM_RIGHT">
<position height="142" width="146" x="315" y="407"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="5" language="java" name="com.iluwatar.composite.Word" project="composite"
file="/composite/src/main/java/com/iluwatar/composite/Word.java" binary="false" corner="BOTTOM_RIGHT">
<position height="124" width="146" x="501" y="407"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<generalization id="6">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="3"/>
</generalization>
<generalization id="7">
<end type="SOURCE" refId="4"/>
<end type="TARGET" refId="3"/>
</generalization>
<association id="8">
<end type="SOURCE" refId="3" navigable="false">
<attribute id="9" name="children"/>
<multiplicity id="10" minimum="0" maximum="2147483647"/>
</end>
<end type="TARGET" refId="3" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<generalization id="11">
<end type="SOURCE" refId="5"/>
<end type="TARGET" refId="3"/>
</generalization>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>

View File

@ -1,43 +0,0 @@
@startuml
package com.iluwatar.composite {
class App {
- LOGGER : Logger {static}
+ App()
+ main(args : String[]) {static}
}
class Letter {
- c : char
+ Letter(c : char)
# printThisAfter()
# printThisBefore()
}
abstract class LetterComposite {
- children : List<LetterComposite>
+ LetterComposite()
+ add(letter : LetterComposite)
+ count() : int
+ print()
# printThisAfter() {abstract}
# printThisBefore() {abstract}
}
class Messenger {
+ Messenger()
~ messageFromElves() : LetterComposite
~ messageFromOrcs() : LetterComposite
}
class Sentence {
+ Sentence(words : List<Word>)
# printThisAfter()
# printThisBefore()
}
class Word {
+ Word(letters : List<Letter>)
# printThisAfter()
# printThisBefore()
}
}
LetterComposite --> "-children" LetterComposite
Letter --|> LetterComposite
Sentence --|> LetterComposite
Word --|> LetterComposite
@enduml

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

View File

@ -51,9 +51,7 @@ public class App {
LetterComposite orcMessage = new Messenger().messageFromOrcs();
orcMessage.print();
LOGGER.info("\n");
LOGGER.info("Message from the elves: ");
LOGGER.info("\nMessage from the elves: ");
LetterComposite elfMessage = new Messenger().messageFromElves();
elfMessage.print();

View File

@ -39,9 +39,4 @@ public class Letter extends LetterComposite {
protected void printThisBefore() {
System.out.print(c);
}
@Override
protected void printThisAfter() {
// nop
}
}

View File

@ -42,9 +42,9 @@ public abstract class LetterComposite {
return children.size();
}
protected abstract void printThisBefore();
protected void printThisBefore() {}
protected abstract void printThisAfter();
protected void printThisAfter() {}
/**
* Print

View File

@ -40,11 +40,6 @@ public class Sentence extends LetterComposite {
}
}
@Override
protected void printThisBefore() {
// nop
}
@Override
protected void printThisAfter() {
System.out.print(".");

View File

@ -44,9 +44,4 @@ public class Word extends LetterComposite {
protected void printThisBefore() {
System.out.print(" ");
}
@Override
protected void printThisAfter() {
// nop
}
}