文章目录
- 【Java设计模式】组合模式:构建灵活的树结构
- 一、概述
- 二、组合设计模式的别名
- 三、组合设计模式的意图
- 四、组合模式的详细解释及实际示例
- 五、Java中组合模式的编程示例
- 六、何时在Java中使用组合模式
- 七、组合模式在Java中的实际应用
- 八、组合模式的优点和权衡
- 九、源码下载
【Java设计模式】组合模式:构建灵活的树结构
一、概述
在Java中,组合模式用于将对象组合成树结构,以表示部分 - 整体层次结构。该模式允许客户端统一对待单个对象和对象的组合。
二、组合设计模式的别名
- Object Tree(对象树)
- Composite Structure(组合结构)
三、组合设计模式的意图
将对象组合成树结构,以表示部分 - 整体层次结构。组合设计模式允许客户端统一对待单个对象和对象的组合。
四、组合模式的详细解释及实际示例
- 实际示例:
- 在一个现实世界的例子中,考虑一个具有复杂组织结构的公司。该公司由各个部门组成,每个部门可以包含子部门,最终包含单个员工。组合设计模式可以用于表示这种结构。每个部门和员工都被视为树结构中的一个节点,其中部门可以包含其他部门或员工,但员工是没有子节点的叶节点。这允许公司统一执行操作,例如计算总工资或打印组织结构图,通过以相同的方式对待单个员工和整个部门。
- 通俗解释:
- 组合设计模式允许客户端统一对待单个对象和对象的组合。
- 维基百科解释:
- 在软件工程中,组合模式是一种分区设计模式。组合模式描述了一组对象应被视为单个对象的实例来处理。组合的意图是将对象“组合”成树结构,以表示部分 - 整体层次结构。实现组合模式可以让客户端统一对待单个对象和对象的组合。
五、Java中组合模式的编程示例
每个句子由单词组成,而单词又由字符组成。这些对象中的每一个都是可打印的,并且它们可以在之前或之后打印一些东西,例如句子总是以句号结尾,单词之前总是有空格。
在这里,我们有基类LetterComposite
和不同的可打印类型Letter
、Word
和Sentence
。
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;}@Overrideprotected 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));}}@Overrideprotected void printThisBefore() {System.out.print(" ");}
}
public class Sentence extends LetterComposite {public Sentence(List<Word> words) {words.forEach(this::add);}@Overrideprotected void printThisAfter() {System.out.print(".");}
}
然后我们有一个信使来传递消息:
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);}
}
然后可以这样使用:
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();
}
控制台输出:
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.
六、何时在Java中使用组合模式
当出现以下情况时使用组合模式:
- 您想要表示对象的部分 - 整体层次结构。
- 您希望客户端能够忽略对象组合和单个对象之间的区别。客户端将统一对待组合结构中的所有对象。
七、组合模式在Java中的实际应用
- 图形用户界面,其中组件可以包含其他组件(例如,包含按钮、标签、其他面板的面板)。
- 文件系统表示,其中目录可以包含文件和其他目录。
- 组织结构,其中一个部门可以包含子部门和员工。
- java.awt.Container和java.awt.Component
- Apache Wicket组件树,参见[Component](https://github.com/apache/wicket/blob/91e154702ab1ff3481ef6cbb04c6044814b7e130/wicket - core/src/main/java/org/apache/wicket/Component.java)和[MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket - core/src/main/java/org/apache/wicket/MarkupContainer.java)
八、组合模式的优点和权衡
优点:
- 简化了客户端代码,因为它可以统一对待组合结构和单个对象。
- 更容易添加新的组件类型,因为现有的代码不需要更改。
权衡:
- 可能会使设计过于通用。可能难以限制组合的组件。
- 可能会使限制组合中组件的类型变得更加困难。
九、源码下载
组合模式示例代码下载
通过本文的介绍,相信大家对Java中的组合模式有了更深入的了解。在实际开发中,合理运用组合模式可以构建灵活的树结构,提高代码的可扩展性和可维护性。