您的位置:首页 > 其它

设计模式系列(二): 组合模式

2016-03-08 19:36 225 查看

意图

以树形结构表示“整体-部分”的层次结构。对单个对象和组合对象拥有一致性的操作体验。

动机

在一些场景下,用户可以使用简单的组件组合复杂的组件,这些复杂的组件又可以组合成更复杂的组件。最简单的实现方法,是对于简单组件分别使用一些类实现,然后再定义一些类,作为这些简单类的容器。

这存在一个明显的问题:使用这些类的代码要区别简单组件和容器,而实际上大多数使用情况下,用户认为他们应用有一致的行为。加入这些区别,使得操作复杂化。

组合(Composite)模式,描述了如何使用递归组合,使用户不需要区分这些类。

组合模式的关键在于一个抽象的类,即可以代表简单组件,又可以代表容器。所有的组件和容器都继承自此抽象类,同时容器类又是基类对象的聚合。

适用性

表示对象的部分-整体层次结构

希望用户忽略组合对象与简单组件的区别

结构

类图



结构图



参与者

Component

为组合中的对象声明接口

实现所有类的默认行为

声明一组接口用于访问和管理 Component的子组件

(可选)在递归结构中定义一个访问父组件的接口,并实现

Leaf

表示叶子节点对象,没有子节点

定义叶子节点的行为

Composite

定义有子组件的组件的行为

存储子组件

实现 Component 中有关于子组件的接口

Client

通过 Component 的接口操作组合组件的对象

协作

Client 使用 Component 的接口与组合结构中的对象交互,叶子节点直接处理请求。Composite 节点通常会转发请求给子节点,转发前后可能会有一些辅助操作

效果

定义了包含基本组件和组合组件的类层次结构

简化了客户端代码

更容易的添加新类型组件

设计变得更一变化

实现折衷

显式的父组件引用(parent reference)

优势

管理组合结构简单化,方便于结构上移和删除操作。支持 Chain of Responsibility 模式

是否是现在 Component 中

如果能够保证父引用的不变式,则可以。这表明,任何一个组件,他的父组件引用所指向的组件,必须将其视为子组件。

最简单的实现方法是,只有在一个组件从一个Composite中添加或移除时,才改变其父引用

共享组件

优势

节省存储空间

难点

组件有多个父组件时,问题变得棘手。解决方法是 Flyweight 模式

最大化组件接口

优势

使得客户端能够忽略不同组件的区别

劣势

违反了基类设计原则,有很多操作Leaf用不到

何处声明子组件管理操作

Component

带来透明性(transparency), 丧失安全性(safety)。因为client可能会访问叶子节点的这些操作

Composite

带来安全性,丧失透明性。任何对叶子节点的操作,导致便以失败。但是,客户端使用时要区分是Leaf还是Composite。

总结

组合模式更青睐于透明性。对于安全性的保证可以引入函数
Composite* GetComposite()
,当时一个Leaf时,返回空指针。

真正的便捷,可以通过定义通用的
Add()
Remove()
接口来解决。默认行为直接返回失败信息,而Composite通过重写这些函数达到应有的效果。

在Component中放入Component列表

优势

便于管理子组件

劣势

浪费空间

折衷

只有在Leaf少的时候,这么做才合适

子组件有序

需要有序时,使用Iterator模式

缓存

缓存能够提升遍历时的性能。但要注意,在节点改变时,通知父节点缓存已经失效。

删除组件责任

父组件在自身被删除时,应负责删除自己的子组件。除非子组件是不可变的或者共享的

存储组件的最佳数据结构

依据不同场景灵活变化。有时甚至需要自己实现一些管理接口和结构。可以参见Interpreter模式
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息