组合模式(Composite Pattern)
概念:
定义:组合模式 允许你将对象组合成树型结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。在大多数情况下,我们可以忽略对象组合和个别对象之间的差别。
在日常生活中我们经常会遇到树型结构的问题,比如典型的公司管理,上司管理不同的下属,下属也可能属于某个部门的上司。
组合模式可以模糊简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
组成:
Component(组合):为组合中的所有对象定义一个接口。包括组合和叶节点。
Leaf(叶节点):叶节点通过实现了 Composite 支持的操作,定义了这内元素的行为。
Composite(组件):定义组件的行为,并且组件也拥有子节点。
例子:
公司雇员例子,CEO 有雇员,雇员中有部门经理,经理地面又有雇员。
组件类:
所有的组件都必须实现该接口,然而叶节点和组合节点的角色不同,所以有些方法可能并不适合某种节点。遇到这种情况时,有时候最好的方式是抛出运行时异常。
public abstract class EmployeeConponent {
private String name;
private String description;
private double salary;
//构造函数,包括姓名、描述、薪水
public EmployeeConponent(String name, String description, double salary) {
this.name = name;
this.description = description;
this.salary = salary;
}
//添加雇员
public void add(EmployeeConponent employeeConponent) {
throw new UnsupportedOperationException();
}
//删除雇员
public void remove(EmployeeConponent employeeConponent) {
throw new UnsupportedOperationException();
}
//获得某一个子节点
public Object getChild(int i) {
throw new UnsupportedOperationException();
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public double getSalary() {
return salary;
}
public void print() {
System.out.print("name:" + name);
System.out.print(" description:" + description);
System.out.println(" salary:" + salary);
}
}
Boss 类:
public class Boss extends EmployeeConponent {
//雇员列表
ArrayList<EmployeeConponent> subordinates;
public Boss(String name, String description, double salary) {
super(name, description, salary);
subordinates = new ArrayList<EmployeeConponent>();
}
@Override
public void add(EmployeeConponent employeeConponent) {
subordinates.add(employeeConponent);
}
@Override
public void remove(EmployeeConponent employeeConponent) {
subordinates.remove(employeeConponent);
}
@Override
public EmployeeConponent getChild(int i) {
return (EmployeeConponent) subordinates.get(i);
}
//打印自己以及雇员
@Override
public void print() {
System.out.print("name:" + super.getName());
System.out.print(" description:" + super.getDescription());
System.out.println(" salary:" + super.getSalary());
for (EmployeeConponent i : subordinates) {
i.print();
}
System.out.println();
}
}
雇员类:
public class Employee extends EmployeeConponent {
public Employee(String name, String description, double salary) {
super(name, description, salary);
}
}
测试类:
public class Client {
public static void main(String[] args) {
Boss CEO = new Boss("Li", "CEO", 25000);
Employee employee1 = new Employee("Zhang", "Employee", 12000);
Employee employee2 = new Employee("Zhao", "Employee", 12000);
Boss manager = new Boss("Wang", "Manager", 20000);
Employee employee3 = new Employee("He", "Employee", 12000);
Employee employee4 = new Employee("Qi", "Empoyee", 12000);
CEO.add(employee1);
CEO.add(employee2);
CEO.add(manager);
manager.add(employee3);
manager.add(employee4);
CEO.print();
}
}
适用场景:
- 当我们想表示对象的部分-整体层次结构(树形结构,如文件系统、雇员关系等)。
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
- 组合模式解耦了客户程序与复杂元素内部结构,从而使客户程序可以向处理简单元素一样来处理复杂元素。
如果你想要创建层次结构,并可以在其中以相同的方式对待所有元素,那么组合模式就是最理想的选择。
优缺点:
优点:
- 高层模块调用简单,组合模式解耦了客户程序与复杂元素内部结构。从而使客户程序可以向处理简单元素一样来处理复杂元素。创建层次结构,并可以在其中以相同的方式对待所有元素。
- 节点可以自由增加。
缺点:
- 在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
依赖倒置原则:要依赖抽象,不要依赖具体类。
这个原则说明:不能让高层组件依赖底层组件,而且,不管是高层组件或底层组件,都应该依赖于抽象。