目录
一、前言
二、透明组合模式
三、安全组合模式
四、总结
一、前言
组合模式(Composite Pattern)是一种结构型设计模式,将对象组合成树形结构以表示“部分-整体”得层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
组合模式由以下角色组成:
Component(抽象组件):
一般是接口或者抽象类,是叶子构件和容器构件对象声明接口,抽象出访问以及管理子构件的方法,可以看做是根节点
Leaf(叶子结点):
在组合中表示叶子节点对象,叶子节点没有子节点,也就没有子构件
Composite(复合节点):
复合节点可以包含子节点,子节点可以是叶子节点,也可以是其他复合节点。可以看做是树枝节点
整个组合模式的结构图:
二、透明组合模式
组合模式分为透明和安全两种方式,在透明方式中,抽象组件中会声明所有类中的方法,客户端无法区别树叶对象和树枝对象,对客户端是透明的。但在树叶节点中,本来没有添加、删除放大,但却要实现它,是没有意义的。
比如公司组织建构,公司有总公司,总公司下有财务部门、技术部门等,还有分公司,分公司也有财务部门,技术部门等。如果按照传统方式,总公司的财务部门、技术部门等需要代码实现,分公司的财务部门、技术部门也需要代码实现,但现实中这些部门的职责差不多,分公司其实可以复用总公司的财务部门、技术部门类。
根据组合模式,我们便有以下代码实现:
抽象组件Component类,即根节点:
public abstract class Component {abstract void add(Component component);abstract void remove(Component component);abstract void display(int depth);abstract void operation();
}
复合节点Composite类,即树枝节点:
public class Composite extends Component{private List<Component> children = new ArrayList<>();private String name;public Composite(String name) {this.name = name;}@Overridevoid add(Component component) {children.add(component);}@Overridevoid remove(Component component) {children.remove(component);}@Overridevoid display(int depth) {System.out.println("深度:" + depth + " 名称:" + name);for (Component component : children) {component.display(depth + 1);}}@Overridevoid operation() {for (Component component : children){component.operation();}}
}
叶子节点财务部门LeafOne类:
public class LeafOne extends Component{private String name;public LeafOne(String name) {this.name = name;}@Overridevoid add(Component component) {}@Overridevoid remove(Component component) {}@Overridevoid display(int depth) {System.out.println("深度:" + depth + " 名称:" + name);}@Overridevoid operation() {System.out.println(name + "财务操作");}
}
叶子节点财务部门LeafTwo类:
public class LeafTwo extends Component{private String name;public LeafTwo(String name) {this.name = name;}@Overridevoid add(Component component) {}@Overridevoid remove(Component component) {}@Overridevoid display(int depth) {System.out.println("深度:" + depth + " 名称:" + name);}@Overridevoid operation() {System.out.println(name + "技术操作");}
}
客户端调用类:
public class Client {public static void main(String[] args) {Component component = new Composite("北京总公司");component.add(new LeafOne("北京总公司财务部门"));component.add(new LeafTwo("北京总公司技术部门"));Component component1 = new Composite("上海分公司");component1.add(new LeafOne("上海分公司财务部门"));component1.add(new LeafTwo("上海分公司技术部门"));component.add(component1);Component component2 = new Composite("深圳分公司");component2.add(new LeafOne("深圳分公司财务部门"));component2.add(new LeafTwo("深圳分公司技术部门"));component.add(component2);System.out.println("公司架构:");component.display(1);System.out.println("职能:");component.operation();}
}
运行结果:
三、安全组合模式
相较于透明方式的组合模式,安全方式主要在抽象组件中不包含添加、删除操作,客户端调用中区分复合节点和叶子节点。
抽象组件Component类:
public abstract class Component {abstract void display(int depth);abstract void operation();
}
复合节点Composite类:
public class Composite extends Component{private List<Component> children = new ArrayList<>();private String name;public Composite(String name) {this.name = name;}public void add(Component component) {children.add(component);}public void remove(Component component) {children.remove(component);}@Overridevoid display(int depth) {System.out.println("深度:" + depth + " 名称:" + name);for (Component component : children) {component.display(depth + 1);}}@Overridevoid operation() {for (Component component : children){component.operation();}}
}
叶子节点财务部门LeafOne类:
public class LeafOne extends Component {private String name;public LeafOne(String name) {this.name = name;}@Overridevoid display(int depth) {System.out.println("深度:" + depth + " 名称:" + name);}@Overridevoid operation() {System.out.println(name + "财务操作");}
}
叶子节点财务部门LeafTwo类:
public class LeafTwo extends Component{private String name;public LeafTwo(String name) {this.name = name;}@Overridevoid display(int depth) {System.out.println("深度:" + depth + " 名称:" + name);}@Overridevoid operation() {System.out.println(name + "技术操作");}
}
客户端调用:
public class Client {public static void main(String[] args) {Composite composite = new Composite("北京总公司");composite.add(new LeafOne("北京总公司财务部门"));composite.add(new LeafTwo("北京总公司技术部门"));Composite composite1 = new Composite("上海分公司");composite1.add(new LeafOne("上海分公司财务部门"));composite1.add(new LeafTwo("上海分公司技术部门"));composite.add(composite1);Composite composite2 = new Composite("深圳分公司");composite2.add(new LeafOne("深圳分公司财务部门"));composite2.add(new LeafTwo("深圳分公司技术部门"));composite.add(composite2);System.out.println("公司架构:");composite.display(1);System.out.println("职能:");composite.operation();}
}
运行结果:
四、总结
优点与缺点
优点:
1、高层模块(客户端)调用简单。组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码
2、节点自由增加,更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”
缺点:
1、在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则
2、设计较复杂,客户端需要花更多时间理清类之间的层次关系
3、不容易限制容器中的构件
4、不容易用继承的方法来增加构件的新功能
使用场景:
当需求中是体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑组合模式。
Spring中IOC就使用到组合模式,通过将组件组合成树形结构,实现了对象的依赖关系管理和生命周期控制。比如Spring中的CompositeCacheManager,Spring用来管理多个CacheManager的复合类。
文件系统:
组合模式可以用来表示文件系统的层次结构,使得客户端可以以统一的方式操作文件和文件夹,例如创建、删除、移动等。
组织机构:
组合模式可以用于表示组织机构的层次结构,例如公司的组织结构可以以树形结构来表示,根节点表示公司,子节点表示部门,叶子节点表示员工。使用组合模式可以统一地管理公司的组织结构,例如添加、删除部门或员工,查找某个部门的员工等。
图形界面控件:
图形界面中的控件可以被看作是一个层次结构,例如窗口控件可以包含按钮控件和文本框控件,按钮控件又可以包含图片控件等。组合模式可以用来表示控件的层次结构,使得客户端可以以统一的方式操作控件,例如添加、删除、遍历等。
菜单和菜单项:
在图形界面中,菜单可以包含菜单项,菜单项可以是子菜单或者普通的操作项。组合模式可以用来表示菜单和菜单项的层次结构,使得客户端可以以统一的方式操作菜单和菜单项,例如添加、删除、遍历等。