内容简介:将对象组合成树形结构来表现出“整体/部分”的层次结构。组合能让客户以一致性的方式处理个别的对象以及对象组合。抽象组件(Component): 为组合中的对象(节点或者组件)声明接口,也可提供默认的接口缺省实现;节点对象(Leaf): 组合中的叶节点对象,叶节点对象不再拥有子节点;
将对象组合成树形结构来表现出“整体/部分”的层次结构。组合能让客户以一致性的方式处理个别的对象以及对象组合。
主要组成
抽象组件(Component): 为组合中的对象(节点或者组件)声明接口,也可提供默认的接口缺省实现;
节点对象(Leaf): 组合中的叶节点对象,叶节点对象不再拥有子节点;
复合对象(Composite):允许存在多个子部件,需要包含的子部件,并实现对子部件的操作接口;
客户端(Client): 调用端,通过调用Component相关接口,操作组合中的对象;
UML图
透明模式:叶节点和组合对象所拥有的操作都放抽象组件Component,这样客户端调用时,不需要判断节点类型都可以进行api调用,无需类型转换。但是对应的存在安全性的问题,因为叶节点本身并不具备组合对象add、remove、get等等有关子节点的操作api,这样的设计可能导致调用后出现与预期不符的现象,因为客户有可能会做一些无意义 的事情,例如在Leaf 中增加和删除对象等。
安全模式:将组合对象独有的api操作都放在对应的实现类中,好处就是安全性提升,只有组合对象才会提供add、remove、get等操作。缺点就是不够透明,整个树形结构元素使用上,因为Leaf 和Composite具有不同的接口,客户还得区分判断是叶节点或者组合对象,并进行类型转换才可以调用相应的api;
2种方式在于透明性和安全性的互换,这需要在安全性和透明性之间做出权衡选择,在这一模式中,相对于安全性,我们比较强调透明性。如果你选择了安全性,有时你可能会丢失类型信息,并且不得不将一个组件转换成一个组合。这样的类型转换必定不是类型安全的。
框架代码
这边以透明模式为例:
抽象组件(Component):
将默认实现为抛出异常(也可空实现之类的,具体情况具体分析),子类根据需要进行重写
public abstract class Component { public abstract void operation(); public void add(Component component) { throw new UnsupportedOperationException(); } public void remove(Component component) { throw new UnsupportedOperationException(); } public Component get(int index) { throw new UnsupportedOperationException(); } } 复制代码
节点对象(Leaf):
public class Leaf extends Component{ @Override public void operation() { //... System.out.println("叶节点自身的操作"); } } 复制代码
复合对象(Composite):
public class Composite extends Component{ List<Component> components = new ArrayList<Component>(); @Override public void add(Component component) { components.add(component); } @Override public void remove(Component component) { components.remove(component); } @Override public Component get(int index) { return components.get(index); } @Override public void operation() { for (Component component : components) { component.operation(); } } } 复制代码
Client中调用:
//创建过程一般是对调用端隐藏,Client不需要关系是创建的什么对象 Component component = new Composite(); Component leaf1 = new Leaf(); Component leaf2 = new Leaf(); component.add(leaf1); List<Component> list = new ArrayList<>(); list.add(component); list.add(leaf2); //Client只要执行自己所需要的操作就行 for (Component component : list) { component.operation(); } 复制代码
具体例子
熟悉的windows文件目录结构就可以看出是组合模式中的树状图。节点可以是文件(Leaf),也可以是目录(Compostite),可以定义出共同的抽象组件(Component)提供接口: open、delete等相关文件操作。
UML图
代码
AbstractFile抽象文件(Component):
public abstract class AbstractFile { String fileName; public AbstractFile(String fileName) { this.fileName = fileName; } public abstract void open(); public abstract void delete(); public abstract boolean isDirect(); public void add(AbstractFile abstractFile) { throw new UnsupportedOperationException(); } public void remove(AbstractFile abstractFile) { throw new UnsupportedOperationException(); } public AbstractFile get(int index) { throw new UnsupportedOperationException(); } } 复制代码
File文件叶节点(Leaf):
public class File extends AbstractFile{ public File(String fileName) { super(fileName); } @Override public void open() { System.out.println("打开文件" + fileName); } @Override public void delete() { System.out.println("删除文件" + fileName); } @Override public boolean isDirect() { return false; } } 复制代码
Directory目录节点(Composite)
public class Directory extends AbstractFile{ List<AbstractFile> files = new ArrayList<>(); public Directory(String fileName) { super(fileName); } @Override public void add(AbstractFile abstractFile) { files.add(abstractFile); } @Override public void remove(AbstractFile abstractFile) { files.remove(abstractFile); } @Override public AbstractFile get(int index) { return files.get(index); } @Override public void open() { for (AbstractFile abstractFile : files) { abstractFile.open(); } } @Override public void delete() { for (AbstractFile abstractFile : files) { abstractFile.delete(); } } @Override public boolean isDirect() { return true; } } 复制代码
客户端调用
假设进行文件删除:
AbstractFile directory = new Directory("目录"); AbstractFile file1 = new File("文件1"); AbstractFile file2 = new File("文件2"); directory.add(file1); List<AbstractFile> list = new ArrayList<>(); list.add(directory); list.add(file2); for (AbstractFile abstractFile : list) { abstractFile.delete(); } 复制代码
假设不使用组合模式
已上诉文件目录例子为例,则会导致在一个文件集合中需要针对性的判断该文件类型:
Directory directory = new Directory("目录"); File file1 = new File("文件1"); File file2 = new File("文件2"); List<Object> list = new ArrayList<>(); list.add(directory); list.add(file1); list.add(file2); for (Object object : list) { if (object instanceof File) { //.... } if (object instanceof Directory) { //.... } } 复制代码
总结
优点
使得使用方能够以一致性的方式调用接口,来处理对象,而不必关心这个对象是单个叶节点还是一个组合的对象结构。
缺点
安全性与透明性的考虑
应用场景
有一系列对象集合,并且这些对象集合有明显的"整体/部分"的关系,可以构建成树形结构。
以上所述就是小编给大家介绍的《小白设计模式:组合模式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 设计模式——订阅模式(观察者模式)
- 设计模式-简单工厂、工厂方法模式、抽象工厂模式
- java23种设计模式-门面模式(外观模式)
- 设计模式-享元设计模式
- Java 设计模式之工厂方法模式与抽象工厂模式
- JAVA设计模式之模板方法模式和建造者模式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。