源码地址 | https://github.com/DingMouRen/DesignPattern |
---|
- Component抽象根节点,为组合中的对象声明接口。在适当的情况下,可以实现所有类共有接口的缺省行为。声明一个接口用于访问和管理Component的子节点。(可选)可在递归结构中定义一个接口,用于访问一个父节点,并在适合的情况下实现它。
- Composite定义有子节点的那些枝干节点的行为,存储子节点,在Component接口中实现与子节点有关的操作
- Leadf在组合中表示叶子节点的对象,叶子节点没有子节点,在组合中定义节点对象的行为。
定义
组合模式将对象组合成树形结构来表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
使用场景
- 表示对象的部分-整体层次结构
- 从一个整体中能够独立出部分模块或者功能的场景
- 希望忽略组合对象与单个对象的不同,用户将统一的使用组合结构中的所有对象
协作
用户使用Component类接口 与组合结构中的对象进行交互。如果接收者是一个叶节点,那么久直接处理请求。如果接收者是Composite,它通常将请求发送给它的子部件,在转发请求之前或之后可能执行一些辅助操作。
举个栗子
我们电脑都有这样的结构:文件夹与文件,这是典型的组合模式的例子,这是透明的组合模式,叶节点与枝干节点有相同的结构,安全的组合模式请看源码中的例子。
//抽象根节点表示文件夹和文件的抽象类
public abstract class Dir {
//存储文件夹下所有的元素
protected List<Dir> dirs = new ArrayList<>();
//当前文件夹或者文件的名称
private String name;
public Dir(String name) {
this.name = name;
}
//添加一个文件或者文件夹
public abstract void addDir(Dir dir);
//移除一个文件或者文件夹
public abstract void removeDir(Dir dir);
//清空文件夹下所有的元素
public abstract void clear();
//输出文件夹目录结构
public abstract void showStructure(int level);
//获取文件夹下所有的文件或者子文件夹
public abstract List<Dir> getDirs();
//获取文件或文件夹名称
public String getName() {
return name;
}
}
//具体实现类,表示文件夹类,但是结构与子节点是一样的,
public class Folder extends Dir {
public Folder(String name) {
super(name);
}
@Override
public void addDir(Dir dir) {
dirs.add(dir);
}
@Override
public void removeDir(Dir dir) {
dirs.remove(dir);
}
@Override
public void clear() {
dirs.clear();
}
@Override
public void showStructure(int level) {
for (int i = 0; i < level; i++) {
System.out.print("-");
}
System.out.println(getName());
Iterator<Dir> iterator = dirs.iterator();
while (iterator.hasNext()){
iterator.next().showStructure(level + 3);
}
}
@Override
public List<Dir> getDirs() {
return dirs;
}
}
//表示文件类,跟文件夹是相同的结构
public class File extends Dir{
public File(String name) {
super(name);
}
@Override
public void addDir(Dir dir) {
throw new UnsupportedOperationException("文件不支持该操作");
}
@Override
public void removeDir(Dir dir) {
throw new UnsupportedOperationException("文件不支持该操作");
}
@Override
public void clear() {
throw new UnsupportedOperationException("文件不支持该操作");
}
@Override
public void showStructure(int level) {
for (int i = 0; i < level; i++) {
System.out.print("-");
}
System.out.println(getName());
}
@Override
public List<Dir> getDirs() {
throw new UnsupportedOperationException("文件不支持该操作");
}
}
使用
public static void main(String[] args) {
//构造一个根目录对象C
Dir diskC = new Folder("C盘");
//根目录C下添加一个mp3文件
diskC.addDir(new File("NeedYouNow.mp3"));
//根目录C下添加三个子目录windows user programfile
Dir windows = new Folder("windows");
diskC.addDir(windows);
Dir user = new Folder("user");
diskC.addDir(user);
Dir programfile = new Folder("programfile");
diskC.addDir(programfile);
//windows目录下添加qq.exe文件,user目录下添加info.txt文件,programfile目录下添加触不可及(法国版).mp4
windows.addDir(new File("qq.exe"));
windows.addDir(new File("weixin.exe"));
user.addDir(new File("info.txt"));
user.addDir(new File("data.txt"));
programfile.addDir(new File("触不可及(法国版).mp4"));
programfile.addDir(new File("战狼2.mp4"));
//打印出根目录结构
diskC.showStructure(0);
}
总结
组合模式在android的应用,比如一些界面UI架构的设计,Android目录选择器。
优点:
- 清晰定义分层次的复杂对象,让高层模块忽略层次的差异,方便对整个层次结构进行控制
- 简化高层模块的代码,添加枝干构件和叶子构件很方便,符合开闭原则
缺点:
在新增构件时不好对枝干中的构件类型进行限制,它们都来自相同的抽象层,所以必须进行类型检查来实现。
网友评论