概述
组合模式也称为部分整体模式,是结构型设计模式,组合模式将一组相似的对象看作一个对象处理.
并根据一个树状结构来组合对象,然后提供一个统一的方法去访问相应的对象,以此忽略掉对象与对象集合之间的差别.当组合体一个对象的一个方法被调用执行时,
Composite将遍历(Iterator)整个树形结构,寻找同样包含这个方法的对象并实现调用执行
定义
将对象组合成树形结构以表示”部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性.
使用场景
- 表示对象的部分-整体层次结构时
- 从一个整体中能够独立出部分模块或功能的场景
UML
其中涉及到的角色介绍:
Component
: 抽象根节点,在适当的情况下,实现所有类共有接口的缺省行为.声明一个接口用于访问和管理Component
子部件。Composite
: 定义有子节点的那些枝干节点的行为,存储子节点,在Component
接口中实现与子节点有关的操作Leaf
: 在组合中表示叶子节点对象,叶子节点没有子节点,在组合中定义节点对象的行为.Client
: 客户端对象,通过Component
操作组合节点的对象
实例
比较典型的组合模式使用场景就是文件夹系统了,如下就是通过文件夹模拟组合模式的使用
- 首先定义文件和文件夹的抽象,相当于
Component
角色
public abstract class Dir {
/**
* 声明一个List成员变量存储文件夹下的所有元素
*/
protected List<Dir>mDirs = new ArrayList<>();
private String name;
public Dir(String _name) {
name = _name;
}
public abstract void addDir(Dir _dir);
public abstract void rmDir(Dir _dir);
public abstract void clear();
public abstract void print();
public abstract List<Dir> getFiles();
public String getName() {
return name;
}
}
- 接下来定义文件夹对象,相当于
Composite
public class Folder extends Dir {
private static final String TAG = "Folder";
public Folder(String _name) {
super(_name);
}
@Override public void addDir(Dir _dir) {
mDirs.add(_dir);
}
@Override public void rmDir(Dir _dir) {
mDirs.remove(_dir);
}
@Override public void clear() {
mDirs.clear();
}
@Override public void print() {
Log.d(TAG, "print: --->" + getName() + "(");
Iterator<Dir> iter = mDirs.iterator();
while (iter.hasNext()) {
Dir dir = iter.next();
dir.print();
if (iter.hasNext()) {
Log.d(TAG, "print: -->" + ",");
}
}
Log.d(TAG, "print: -->" + ")");
}
@Override public List<Dir> getFiles() {
return mDirs;
}
}
- 文件对象,没有子节点,相当于
Leaf
public class File extends Dir {
private static final String TAG = "File";
public File(String _name) {
super(_name);
}
@Override public void addDir(Dir _dir) {
throw new UnsupportedOperationException("文件对象不支持该操作");
}
@Override public void rmDir(Dir _dir) {
throw new UnsupportedOperationException("文件对象不支持该操作");
}
@Override public void clear() {
throw new UnsupportedOperationException("文件对象不支持该操作");
}
@Override public void print() {
Log.d(TAG, "print: -->"+getName());
}
@Override public List<Dir> getFiles() {
throw new UnsupportedOperationException("文件对象不支持该操作");
}
}
Client
客户端对象调用示例
Dir diskC = new Folder("C");
diskC.addDir(new File("sss.text"));
Dir dirW = new Folder("Windows");
dirW.addDir(new File("explorer.exe"));
Dir dirP = new Folder("PerfLogs");
dirP.addDir(new File("bbb.text"));
Dir dirF = new Folder("Program File");
dirF.addDir(new File("ftp.text"));
diskC.addDir(dirW);
diskC.addDir(dirP);
diskC.addDir(dirF);
diskC.print();
模式特点
优点:
- 组合模式可以清楚的定义分层次的复杂对象,表示对象的全部或部分层次.同时,让高层次模块忽略了层次的差异,方便对整个层次结构进行控制.
- 高层模块可以一致的使用一个组合结构或其中的单个对象,不用关心处理的是单个对象还是组合结构.
- 新增新的枝干构件很方便,无需修改原来的文件,符合开闭原则.
缺点:
- 在新增构件时不好对枝干中的构件类型进行限制,不能依赖类型系统来施加这些约束,因为他们都来自形同的抽象层.