组合模式
1.模式机动
-
在树形目录结构中,包含文件和文件夹两类不同的元素
- 在文件夹中可以包含文件,还可以继续包含子文件夹
- 在文件中不能再包含子文件或者子文件夹
-
文件夹–> 容器(Container)
-
文件 --> 叶子(Leaf)
-
如何将容器对象和叶子对象进行递归组合,使得用户在使用时无须对它们进行区分,可以一致地对待容器对象和叶子对象?–>组合模式
2.模式定义
- 组合模式(Composite Pattern):组合多个对象形成树形结构以表示**“部分-整体”的结构层次**。组合模式对**单个对象(即叶子对象)和组合对象(即容器对象)**的使用具有一致性。
- 对象结构型模式
- 将对象组织到树形结构中,可以用来描述整体与部分的关系
3. 模式结构
组合模式包含如下角色:
- Component: 抽象构件
- Leaf: 叶子构件
- Composite: 容器构件
模式结构
4. 模式分析
文件系统组合模式结构图
容器构件示例代码:
public class Composite extends Component {
private ArrayList<Component> list = new ArrayList<Component>();
public void add(Component c) {
list.add(c);
}
public void remove(Component c) {
list.remove(c);
}
public Component getChild(int i) {
return (Component)list.get(i);
}
public void operation() {
//容器构件具体业务方法的实现,将递归调用成员构件的业务方法
for(Object obj:list) {
((Component)obj).operation();
}
}
}
透明组合模式
- 抽象构件Component中声明了所有用于管理成员对象的方法,包括add()、remove(),以及getChild()等方法
- 在客户端看来,叶子对象与容器对象所提供的方法是一致的,客户端可以一致地对待所有的对象
- 缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的
安全组合模式
- 抽象构件Component中没有声明任何用于管理成员对象的方法,而是在Composite类中声明并实现这些方法
- 对于叶子对象,客户端不可能调用到这些方法
- 缺点是不够透明,客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件
5.模式实例
水果盘:实例说明
- 在水果盘(Plate)中有一些水果,如苹果(Apple)、香蕉(Banana)、梨子(Pear),当然大水果盘中还可以有小水果盘,现需要对盘中的水果进行遍历(吃),当然如果对一个水果盘执行“吃”方法,实际上就是吃其中的水果。使用组合模式模拟该场景。
水果盘:参考类图
6.组合模式的优缺点
组合模式优点:
-
可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,让客户端忽略了层次的差异,方便对整个层次结构进行控制
-
客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码
-
增加新的容器构件和叶子构件都很方便,符合开闭原则
-
为树形结构的面向对象实现提供了一种灵活的解决方案
组合模式缺点:
- 在增加新构件时很难对容器中的构件类型进行限制
7.使用场景
在以下情况下可以使用组合模式:
- 在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致地对待它们
- 在一个使用面向对象语言开发的系统中需要处理一个树形结构
- 在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,需要增加一些新的类型
8.模式扩展
更复杂的组合模式