组合模式
一、定义
摘自百度百科: 组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构。
点击查看源码
二、角色分类
抽象构件(Component)
声明了参与组合对象的共有方法和属性,定义了访问其子构件的方法
叶子构件(Leaf)
其表示叶子节点,叶子节点没有子节点,是遍历的最小单位,它实现了在抽象构件中定义的一些行为,
树枝构件(Composite)
它的作用是组合树枝节点和叶子节点构成一个树枝结构,它提供了一个集合来存储子节点,并且实现了抽象构件中定义的行为,包括访问和管理子构件的方法
客户角色(Client)
调用方法的角色
三、实现方式
UML图
![未命名文件](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
具体实现
透明模式
抽象构件(Component)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public abstract class Component { public void operation() { } public abstract void add(Component component);
public abstract void remove(Component component);
public abstract List<Component> getChildren(); }
|
树枝构件(Composite)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Composite extends Component { private List<Component> componentList = new ArrayList<>();
public void add(Component component) { this.componentList.add(component); }
public void remove(Component component) { this.componentList.remove(component); }
public List<Component> getChildren() { return this.componentList; } }
|
叶子构件(Leaf)
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Leaf extends Component { public void add(Component component) { }
public void remove(Component component) { }
public List<Component> getChildren() { } }
|
客户角色(Client)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class Client { public static void main(String[] args) { Composite root = new Composite(); root.operation(); Composite branch = new Composite(); Leaf leaf = new Leaf(); root.add(branch); branch.add(leaf); }
public static void showTree(Component root) { root.getChildren.foreach(any->{ if(any instanceof Leaf) { any.operation(); }else { showTree(any); } }); } }
|
安全模式
抽象构件(Component)
1 2 3 4 5 6 7
| public abstract class Component { public void operation() { System.out.println("Component: operation被执行了"); } }
|
树枝构件(Composite)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class Composite extends Component {
private List<Component> componentList = new ArrayList<>();
public void add(Component component) { this.componentList.add(component); }
public void remove(Component component) { this.componentList.remove(component); }
public List<Component> getChildren() { return this.componentList; }
}
|
叶子构件(Leaf)
1 2 3 4 5 6 7
| public class Leaf extends Component {
public void operation() { System.out.println("Leaf: operation被执行了"); }
}
|
客户角色(Client)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class Client { public static void main(String[] args) { Composite root = new Composite(); root.operation(); Composite branch = new Composite(); Leaf leaf = new Leaf(); root.add(branch); branch.add(leaf); showTree(root); }
public static void showTree(Composite root){ for(Component c:root.getChildren()){ if(c instanceof Leaf){ c.operation(); }else{ showTree((Composite)c); } } } }
|
透明模式和安全模式的区别
- 安全模式在抽象组件中只定义一些默认的行为或属性,它是把树枝节点和树叶节点彻底分开;透明模式是把用来组合使用的方法放到抽象类中,不管叶子对象还是树枝对象都有相同的结构,通过判断确认是叶子节点还是树枝节点,如果处理不当,这个会在运行期出现问题,不是很建议的方式。
- 安全模式与依赖倒置原则冲突;透明模式的好处就是它基本遵循了依赖倒转原则,方便系统进行扩展。
- 安全模式在遍历树形结构的的时候需要进行强制类型转换;在透明模式下,遍历整个树形结构是比较容易的,不用进行强制类型转换。
四、应用场景
以下部分内容摘自 菜鸟教程
意图: 将对象组合成树形结构以表示”部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
主要解决: 它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
何时使用:
- 您想表示对象的部分-整体层次结构(树形结构)。
- 您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
如何解决: 树枝和叶子实现统一接口,树枝内部组合该接口。
关键代码: 树枝内部组合该接口,并且含有内部属性 List,里面放 Component。
应用实例:
- 算术表达式包括操作数、操作符和另一个操作数,其中,另一个操作数也可以是操作数、操作符和另一个操作数。
- 在 JAVA AWT 和 SWING 中,对于 Button 和 Checkbox 是树叶,Container 是树枝。
使用场景: 部分、整体场景,如树形菜单,文件、文件夹的管理。
注意事项: 定义时为具体类。
五、优缺点
优点
- 高层模块调用简单。
- 节点自由增加。
缺点
在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。