设计模式之组合模式

概念

组合模式(Composite),将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性

优点

  • 简化了客户端代码,统一地处理复合结构和单个对象
  • 更容易添加新类型的组件,不需要更改现有代码

什么时候使用组合模式

  • 你希望表示对象的部分-整体层次结构
  • 你希望客户端能够忽略对象组合和单个对象之间的差异。客户端将统一地对待复合结构中的所有对象

示例

每个句子都是由单词组成的,而单词又由字符组成。每一个对象都是可打印的,在它们之前或之后都可以打印一些东西,比如句子总是以句号结束,单词总是在它之前有空格。 这里我们有基类LetterComposite和不同的可打印类型Letter, Word和Sentence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public abstract class LetterComposite {

private final 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();
children.forEach(LetterComposite::print);
printThisAfter();
}
}

public class Letter extends LetterComposite {

private final char character;

public Letter(char c) {
this.character = c;
}

@Override
protected void printThisBefore() {
System.out.print(character);
}
}

public class Word extends LetterComposite {

public Word(List<Letter> letters) {
letters.forEach(this::add);
}

public Word(char... letters) {
for (char letter : letters) {
this.add(new Letter(letter));
}
}

@Override
protected void printThisBefore() {
System.out.print(" ");
}
}

public class Sentence extends LetterComposite {

public Sentence(List<Word> words) {
words.forEach(this::add);
}

@Override
protected void printThisAfter() {
System.out.print(".");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Messenger {

LetterComposite messageFromOrcs() {

var words = List.of(
new Word('W', 'h', 'e', 'r', 'e'),
new Word('t', 'h', 'e', 'r', 'e'),
new Word('i', 's'),
new Word('a'),
new Word('w', 'h', 'i', 'p'),
new Word('t', 'h', 'e', 'r', 'e'),
new Word('i', 's'),
new Word('a'),
new Word('w', 'a', 'y')
);

return new Sentence(words);

}

LetterComposite messageFromElves() {

var words = List.of(
new Word('M', 'u', 'c', 'h'),
new Word('w', 'i', 'n', 'd'),
new Word('p', 'o', 'u', 'r', 's'),
new Word('f', 'r', 'o', 'm'),
new Word('y', 'o', 'u', 'r'),
new Word('m', 'o', 'u', 't', 'h')
);

return new Sentence(words);

}

}
1
2
3
4
5
6
7
8
9
10
  public static void main(String[] args) {

var messenger = new Messenger();

LOGGER.info("Message from the orcs: ");
messenger.messageFromOrcs().print();

LOGGER.info("Message from the elves: ");
messenger.messageFromElves().print();
}
1
2
3
4
20:43:54.801 [main] INFO com.iluwatar.composite.App -- Message from the orcs: 
Where there is a whip there is a way.
20:43:54.803 [main] INFO com.iluwatar.composite.App -- Message from the elves:
Much wind pours from your mouth.

组合模式的两种实现:透明模式和安全模式

注意事项

  • 会使设计过于一般化。限制组合的某些组件可能比较困难
  • 限制组合中组件的类型变得更加困难
    组合模式的主要优点–统一对待单个物体和复合物体–也是它的主要弱点。通过将设计推广到处理范围广泛的场景,模式牺牲了特定性,使其更难强制执行约束,并导致潜在的误用或意外行为。这种权衡是模式本身固有的,在决定是否在给定上下文中使用它时必须仔细考虑

设计模式之组合模式
http://s1mplecode.com/design-pattern/composite.html
作者
Jago
发布于
2025年1月1日
许可协议