组合模式 gaunthan Posted on Feb 6 2017 ? Design Patterns ? > **组合模式**(Composite Pattern)允许将对象组合成树形结构来表现”整体/部分“层次结构。组合使客户可以用一致的方式处理对象集合和单个对象。 <!--more--> ## 概述 使用组合结构,我们能把相同的操作应用在组合和个别对象上。换句话说,在大多数情况下,我们可以忽略对象组合和个别对象之间的差别。这种思想和[广义表](https://zh.wikipedia.org/wiki/%E5%B9%BF%E4%B9%89%E8%A1%A8)是一样的。 ## 结构 ### 安全性设计 组合模式的类图如下所示:  说明如下: |组件|说明| |--| |Component|为组合中的所有对象定义一个接口,不管是组合还是叶结点。| |Composite|定义组件的行为,而这样的组件具有子结点。它也实现了叶结点相关的操作,注意,其中一些操作可能对于Composite意义不大,因此在这种情况下可能产生异常。| |Leaf|叶结点定义了单个对象的行为。叶结点没有孩子。| ### 透明性设计 还有一种设计对于 Component 抽象类有不同的定义方式。它将 Leaf 和 Composite 的操作都放置在 Component 中,并为每一个操作都提供一个抛出 `UnsupportedOperationException` 的默认实现。换句话说,Leaf 和 Composite 的责任都集中在类 Component 中,这违背了单一责任原则。 另外,由于客户有机会对一个 Component 做一些不恰当或是没有意义的操作,所以失去了一些”安全性“。但是,通过让组件接口同时包含一些管理子结点和叶结点的操作,客户就可以将叶结点和子结点一视同仁。也就是说,一个元素究竟是组合还是叶结点,对客户是透明的。 这种设计下的组合模式,其类图如下所示:  |组件|说明| |--| |Component|为组合中的所有对象定义一个接口,不管是组合还是叶结点。| |Composite|定义组件的行为,而这样的组件具有子结点。它也实现了叶结点相关的操作,注意,其中一些操作可能对于Composite意义不大,因此在这种情况下可能产生异常。| |Leaf|叶结点定义了单个对象的行为。叶结点没有孩子。注意,其中一些操作可能对于Leaf意义不大(如`Add()`、`Remove()`以及`GetChild()`),因此在这种情况下可能产生异常。| ### 总结 在最开始展示的类图中,我们将责任区分在不同的类中。这样一来,设计上就比较安全,但也因此失去了透明性:客户的代码必须用条件语句和`isInstanceof()`操作处理不同类型的结点。 具体选择哪种,与编程风格和应用背景相关。这是一个很典型的折中案例。尽管我们受到设计原则的指导,但是,我们总是需要观察某原则对我们的设计所造成的影响。有时候,我们还会故意做一些看似违反原则的事情。然而,在某些例子中,这仅是观点的问题。 ## References - 弗里曼弗里曼谢拉贝茨 O'ReillyTaiwan 公司 UMLChina. Head First 设计模式 [M]. 中国电力出版社, 2007. 赏 Wechat Pay Alipay Mail Access Protocols: POP3, IMAP 迭代器模式