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) |