这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战
作者的其他平台:
| CSDN:blog.csdn.net/qq\_4115394…
| 知乎:www.zhihu.com/people/1024…
| GitHub:github.com/JiangXia-10…
| 公众号:1024笔记
本文大概3355字,读完共需10分钟
定义:
组合模式(Composite Pattern)又叫做部分-整体模式,它在树型结构(可以想象一下数据结构中的树)的问题中,模糊了简单元素和复杂元素的概念,客户端程序可以像处理简单元素一样来处理复杂元素,而使得客户端程序与复杂元素的内部结构进行解藕。
组合模式一般用来描述整体与部分的关系,它将对象组织到树形结构中,顶层的节点被称为根节点,根节点下面可以包含树枝节点和叶子节点,树枝节点下面又可以包含树枝节点和叶子节点。
如下图的工程目录结构就是一个树型结构:
它可以表示为下面的树型结构图:
由上面的结构图可以发现,根节点和树枝节点其实在本质上属于同一种数据类型,它们都可以作为容器使用;但是叶子节点与树枝节点其实在语义上是不属于同一种类型。但是在组合模式中,是把树枝节点和叶子节点看作属于同一种数据类型(这里是用统一接口定义),从而使得让它们具备一致行为。
所以在组合模式中,整个的树形结构中的对象就会都属于同一种类型,这样的好处就是不需要用户来辨别是树枝节点还是叶子节点,就可以直接进行操作,给用户的使用带来极大的便利。
组成部分:
通过上述对于组合模式的描述,可以总结出组合模式的几个组成部分:
1、Component: 组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件,不管是组合还是叶结点。
2、Leaf: 在组合中表示叶子结点对象,叶子结点没有子结点。
3、Composite: 容器对象,表示参加组合的有子对象的对象,定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加和删除等。
栗子
用上面文件夹的例子,首先声明一个文件夹相关的Component,FolderComponent:
public abstract class FolderComponent {
private String name;
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public FolderComponent() {
}
public FolderComponent(final String name) {
this.name = name;
}
public abstract void add(FolderComponent component);
public abstract void remove(FolderComponent component);
public abstract void display();
}
再声明一个叶子节点文件夹,定义为FileLeaf,并且继承上面的FolderComponent:
public class FileLeaf extends FolderComponent{
public FileLeaf(final String name) {
super(name);
}
@Override
public void add(FolderComponent component) {
}
@Override
public void remove(FolderComponent component) {
}
@Override
public void display() {
System.out.println("叶子文件:" + this.getName());
}
}
最后声明一个容器对象,FolderComposit
public class FolderComposite extends FolderComponent {
private final List<FolderComponent> components;
public FolderComposite(final String name) {
super(name);
this.components = new ArrayList<FolderComponent>();
}
public FolderComposite() {
this.components = new ArrayList<FolderComponent>();
}
@Override
public void add(final FolderComponent component) {
this.components.add(component);
}
@Override
public void remove(final FolderComponent component) {
this.components.remove(component);
}
@Override
public void display() {
System.out.println("文件夹组合容器的名字是" + this.getName());
for (final FolderComponent component : components) {
System.out.println("文件夹组合容器的当前文件夹是" + component.getName());
}
}
}
测试方法:
public class CompositePatternTest {
public static void main(final String[] args) {
final FolderComponent leaf = new FileLeaf("叶子文件");
leaf.display();
final FolderComponent folder = new FolderComposite("文件夹一");
folder.add(new FileLeaf("文件夹里面的文件二"));
folder.add(new FileLeaf("文件夹里面的文件三"));
folder.display();
}
}
运行结果如下:
通过上面的例子可以总结出组合模式的优点和缺点。
组合模式的优点
1、组合模式使得客户端代码可以一致地处理单个对象和组合对象,从而无须关心自己处理的是单个对象,还是组合对象,大大地简化了代码结构;
2、组合模式的使用使得更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,实现了设计模式原则的“开闭原则”;
组合模式的缺点
1、使用组合模式需要花较多地时间理清类之间的层次关系,所以设计较复杂;
2、组合模式理解和设计较为复杂,增加代码难度;
3、如果使用了组合模式就不容易限制容器中的构件;
4、组合模式中不容易用继承的方法来增加构件的新功能;
使用场景
组合模式适用于以下情况:
1、当想要表示对象的部分-整体层次结构
2、当想要用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
总结
使用组合模式方便解耦客户端与复杂元素的内部结构,从而使得客户端程序可以像处理简单元素一样来一致处理复杂元素,大大简化了代码。对于层次结构的系统对象,可以使用组合模式进行处理。
相关推荐:
从零开始学设计模式(三):原型模式(Prototype Pattern)
从零开始学设计模式(四):工厂模式(Factory Pattern)
从零开始学设计模式(五):建造者模式(Builder Pattern)
从零开始学设计模式(六):适配器模式(Adapter Pattern)
从零开始学设计模式(六):代理模式(Proxy Pattern)
从零开始学设计模式(八):装饰器模式(Decorator Pattern)