定義
允許你將對(duì)象組合成樹形結(jié)構(gòu)來表現(xiàn)“整體/部分”層次結(jié)構(gòu)。組合能讓客戶以一致的方式處理個(gè)別對(duì)象以及對(duì)象組合。
使用場(chǎng)景
- 表示對(duì)象的部分 - 整體層次
- 客戶端能夠忽略對(duì)象和單個(gè)對(duì)象的組合之間的差異。 客戶端將統(tǒng)一處理復(fù)合結(jié)構(gòu)中的所有對(duì)象
例子
我們要打印一封信的內(nèi)容。信的內(nèi)容是由句子(sentence)組成,句子由單詞(word)組成,單詞由字母(letter)組成淮摔。遇到字母直接打印出來,單詞的前面輸出空格始赎,句子的末尾輸出句號(hào)和橙。三個(gè)對(duì)象繼承同一對(duì)象,其print方法是一樣的造垛,對(duì)外來看是沒有差別的魔招。
字母組合基類,其包括添加子元素筋搏、迭代執(zhí)行打悠桶佟:
public abstract class LetterComposite {
private List<LetterComposite> children = new ArrayList<>();
public void add(LetterComposite letter) {
children.add(letter);
}
protected abstract void printThisBefore();
protected abstract void printThisAfter();
// 打印的時(shí)候 迭代執(zhí)行
public void print() {
printThisBefore();
for (LetterComposite letter : children) {
letter.print();
}
printThisAfter();
}
}
字母類重寫了printThisBefore方法,此方法打印字母本身:
public class Letter extends LetterComposite {
private char c;
public Letter(char c) {
this.c = c;
}
protected void printThisBefore() {
System.out.print(c);
}
protected void printThisAfter() {
// nop
}
}
單詞類以字母列表為構(gòu)造參數(shù)奔脐,也重寫了printThisBefore方法:
public class Word extends LetterComposite {
public Word(List<Letter> letters) {
for (Letter l : letters) {
this.add(l);
}
}
protected void printThisBefore() {
System.out.print(" ");
}
protected void printThisAfter() {
// nop
}
}
句子類以單詞列表為構(gòu)造參數(shù)俄周,printThisAfter在句子末尾輸出".":
public class Sentence extends LetterComposite {
public Sentence(List<Word> words) {
for (Word w : words) {
this.add(w);
}
}
protected void printThisBefore() {
// nop
}
protected void printThisAfter() {
System.out.print(".");
}
}
構(gòu)造一個(gè)Message類吁讨,用于創(chuàng)建內(nèi)容:
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('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('m'), new Letter('o'), new Letter('u'), new Letter(
't'), new Letter('h'))));
return new Sentence(words);
}
}
打印兩份信的內(nèi)容:
public class App {
public static void main(String[] args) {
System.out.println("Message from the orcs: ");
LetterComposite orcMessage = new Messenger().messageFromOrcs();
orcMessage.print();
System.out.println("Message from the elves: ");
LetterComposite elfMessage = new Messenger().messageFromElves();
elfMessage.print();
}
}
分析
上述的例子中,Sentence峦朗、Word建丧、Letter是三個(gè)層級(jí)的對(duì)象,它們構(gòu)成了樹狀結(jié)構(gòu)波势。
組合模式讓我們能用樹形方式創(chuàng)建對(duì)象的結(jié)構(gòu)翎朱,樹里面包含了組合以及個(gè)別的對(duì)象。
使用組合結(jié)構(gòu)尺铣,我們能把相同的操作應(yīng)用在組合和個(gè)別對(duì)象上拴曲。換句話說,在大多數(shù)情況下凛忿,我么可以忽略對(duì)象組合和個(gè)別對(duì)象之間的差別澈灼。