175 lines
4.9 KiB
Markdown
175 lines
4.9 KiB
Markdown
|
---
|
|||
|
layout: pattern
|
|||
|
title: Composite
|
|||
|
folder: composite
|
|||
|
permalink: /patterns/composite/
|
|||
|
categories: Structural
|
|||
|
tags:
|
|||
|
- Gang of Four
|
|||
|
---
|
|||
|
|
|||
|
## 目的
|
|||
|
|
|||
|
将对象组合成树结构以表示部分整体层次结构。 组合可以使客户统一对待单个对象和组合对象。
|
|||
|
|
|||
|
## 解释
|
|||
|
|
|||
|
真实世界例子
|
|||
|
|
|||
|
> 每个句子由单词组成,单词又由字符组成。这些对象中的每一个都是可打印的,它们可以在它们之前或之后打印一些内容,例如句子始终以句号结尾,单词始终在其前面有空格。
|
|||
|
|
|||
|
通俗的说
|
|||
|
|
|||
|
> 组合模式使客户能够以统一的方式对待各个对象。
|
|||
|
|
|||
|
维基百科说
|
|||
|
|
|||
|
> 在软件工程中,组合模式是一种分区设计模式。组合模式中,一组对象将像一个对象的单独实例一样被对待。组合的目的是将对象“组成”树状结构,以表示部分整体层次结构。实现组合模式可使客户统一对待单个对象和组合对象。
|
|||
|
|
|||
|
**程序示例**
|
|||
|
|
|||
|
使用上面的句子例子。 这里我们有基类`LetterComposite`和不同的可打印类型`Letter`,`Word`和`Sentence`。
|
|||
|
|
|||
|
```java
|
|||
|
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(".");
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
然后我们有一个消息携带者来携带消息。
|
|||
|
|
|||
|
```java
|
|||
|
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);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
然后它可以这样使用:
|
|||
|
|
|||
|
```java
|
|||
|
var orcMessage = new Messenger().messageFromOrcs();
|
|||
|
orcMessage.print(); // Where there is a whip there is a way.
|
|||
|
var elfMessage = new Messenger().messageFromElves();
|
|||
|
elfMessage.print(); // Much wind pours from your mouth.
|
|||
|
```
|
|||
|
|
|||
|
## 类图
|
|||
|
|
|||
|

|
|||
|
|
|||
|
## 适用性
|
|||
|
|
|||
|
使用组合模式当
|
|||
|
|
|||
|
* 你想要表示对象的整体层次结构
|
|||
|
* 你希望客户能够忽略组合对象和单个对象之间的差异。 客户将统一对待组合结构中的所有对象。
|
|||
|
|
|||
|
## 真实世界例子
|
|||
|
|
|||
|
* [java.awt.Container](http://docs.oracle.com/javase/8/docs/api/java/awt/Container.html) and [java.awt.Component](http://docs.oracle.com/javase/8/docs/api/java/awt/Component.html)
|
|||
|
* [Apache Wicket](https://github.com/apache/wicket) component tree, see [Component](https://github.com/apache/wicket/blob/91e154702ab1ff3481ef6cbb04c6044814b7e130/wicket-core/src/main/java/org/apache/wicket/Component.java) and [MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java)
|
|||
|
|
|||
|
## 鸣谢
|
|||
|
|
|||
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
|||
|
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
|
|||
|
* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7)
|