组合模式(Composite)

19-06-18 jdon
              

目的

将对象组合成树结构以表示 部分— 整体 层次结构。Composite允许客户端统一处理单个对象和对象组合。

说明

每个句子都由单词组成,单词又由字符组成。这些对象中的每一个都是可打印的,它们可以在它们之前或之后打印一些内容,例如句子总是以句号结束,单词在它之前总是有空格。

简而言之

复合模式允许客户以统一的方式处理单个对象。

维基百科说

在软件工程中,复合模式是分区设计模式。复合模式描述了一组对象的处理方式与单个对象实例相同。复合的意图是将对象“组合”成树结构以表示 部分 — 整体 层次结构。通过实现复合模式,客户可以统一处理单个对象和组合。

源码示例

以我们上面的句子为例。这里我们有基类和不同的可打印类型

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(".");
  }
}

然后我们有一个信使来传递信息

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

它可以用作

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.

适用场景

  • 您想要表示对象的 部分 — 整体 层次结构。
  • 您希望客户端忽略对象组合和单个对象之间的差异。客户端将统一处理复合结构中的所有对象。