组合模式
1. 介绍
组合模式(Composite Pattern)
是一种结构型模式。将对象进行组合来达到类似于数这种层级关系。
简单理解:假设一个公司只有一个老板,有几个CEO,每一个CEO下面又有1个或多个组长,而每个组长下面又会有若干名员工,这是不是很像数据结构中的树,老板就是根节点,CEO和组长下面可以有若干子节点,而员工就是叶子节点,因为员工下面是没有子节点的(员工不管理任何人)。
优点
- 很方便的表示各个对象之间的层级关系。由于组合模式是用类似于数的结构来组织对象,因此,数这种数据结构能够清晰表示层次关系的优点也被继承下来了。所以,文件系统、公司人员关系等都可以采用组合模式。
- 对象中嵌套其他对象很方便。组合模式中的对象会使用一个链表(其他数据类型)来存储其下一层对象,所以,基本对象可以被组合成更为复杂的对象,而复杂对象可以再次被组合成更复杂的对象,以此类推。
缺点
- 实现比较复杂。因为组合模式会牵扯到数的知识,而数的遍历、节点的删除、查找节点、添加节点又会使用到类似于递归、队列、遍历、查询等知识,是不是头都大了。
- 违反了依赖倒置原则。组合模式中的枝干和叶子都声明成了对象,而不是接口,这违反了依赖倒置原则。
2. 例子
我们使用组合模式来实现一个公司中人员的层次关系。
类图
Employee类
代表员工对象,在对象中使用List(其他数据结构也可以)来储存它的下属对象。
package CompositePattern;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class Employee {
private String name;
private String dept;
private double salary;
private List<Employee> subordinates;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDept() {
return dept;
}
public void setDept(String dept) {
this.dept = dept;
}
public List<Employee> getSubordinates() {
return subordinates;
}
public void setSubordinates(List<Employee> subordinates) {
this.subordinates = subordinates;
}
public Employee(String name, String dept, double salary) {
this.salary = salary;
this.name = name;
this.dept = dept;
subordinates = new ArrayList<Employee>();
}
public boolean add(Employee employee) {
return subordinates.add(employee);
}
public boolean remove(Employee employee) {
return subordinates.remove(employee);
}
@Override
public String toString() {
return "Employee [name=" + name + ", dept=" + dept + ", salary=" + salary + ", subordinates=" + subordinates
+ "]";
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public void dfs() {
dfs(this);
}
//深度优先算法
public void dfs(Employee employee) {
System.out.println(employee.toString());
if (employee != null && !employee.getSubordinates().isEmpty()) {
for (Employee subordinate : employee.subordinates) {
dfs(subordinate);
}
} else {
return;
}
}
//广度优先
public void bfs(Employee employee) {
Stack<Employee> stack = new Stack<Employee>();
stack.add(employee);
while (!stack.isEmpty()) {
System.out.println(stack.peek().toString());
Employee temEmployee = stack.pop();
for (Employee subordinates : temEmployee.getSubordinates()) {
if (subordinates != null) {
stack.add(subordinates);
}
}
}
}
public void bfs() {
bfs(this);
}
}
测试类
构造一个公司的成员逻辑结构,分别调用深度优先和广度优先算法来遍历这个层级结构。
package CompositePattern;
import org.junit.Test;
public class TestJ {
@Test
public void test1() {
Employee header = new Employee("刘老板", "headers", 23000);
Employee CEO1 = new Employee("ceo小明", "ceo", 12000);
Employee CEO2 = new Employee("ceo小红", "ceo", 12000);
Employee groupLeader1 = new Employee("组长", "groupLeader", 6000);
Employee groupLeader2 = new Employee("组长", "groupLeader", 6000);
Employee employee1 = new Employee("员工1", "employee", 2000);
Employee employee2 = new Employee("员工2", "employee", 2000);
Employee employee3 = new Employee("员工3", "employee", 2000);
Employee employee4 = new Employee("员工4", "employee", 2000);
Employee employee5 = new Employee("员工5", "employee", 2000);
groupLeader1.add(employee1);
groupLeader1.add(employee2);
groupLeader2.add(employee3);
groupLeader2.add(employee4);
groupLeader2.add(employee5);
CEO1.add(groupLeader1);
CEO2.add(groupLeader2);
header.add(CEO1);
header.add(CEO2);
//广度优先算法
header.bfs();
System.out.println("-------------------");
//深度优先算法
header.dfs();
}
}
运行结果:
Employee [name=刘老板, dept=headers, salary=23000.0, subordinates=[Employee [name=ceo小明, dept=ceo, salary=12000.0, subordinates=[Employee [name=组长, dept=groupLeader, salary=6000.0, subordinates=[Employee [name=员工1, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工2, dept=employee, salary=2000.0, subordinates=[]]]]]], Employee [name=ceo小红, dept=ceo, salary=12000.0, subordinates=[Employee [name=组长, dept=groupLeader, salary=6000.0, subordinates=[Employee [name=员工3, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工4, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工5, dept=employee, salary=2000.0, subordinates=[]]]]]]]]
Employee [name=ceo小红, dept=ceo, salary=12000.0, subordinates=[Employee [name=组长, dept=groupLeader, salary=6000.0, subordinates=[Employee [name=员工3, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工4, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工5, dept=employee, salary=2000.0, subordinates=[]]]]]]
Employee [name=组长, dept=groupLeader, salary=6000.0, subordinates=[Employee [name=员工3, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工4, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工5, dept=employee, salary=2000.0, subordinates=[]]]]
Employee [name=员工5, dept=employee, salary=2000.0, subordinates=[]]
Employee [name=员工4, dept=employee, salary=2000.0, subordinates=[]]
Employee [name=员工3, dept=employee, salary=2000.0, subordinates=[]]
Employee [name=ceo小明, dept=ceo, salary=12000.0, subordinates=[Employee [name=组长, dept=groupLeader, salary=6000.0, subordinates=[Employee [name=员工1, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工2, dept=employee, salary=2000.0, subordinates=[]]]]]]
Employee [name=组长, dept=groupLeader, salary=6000.0, subordinates=[Employee [name=员工1, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工2, dept=employee, salary=2000.0, subordinates=[]]]]
Employee [name=员工2, dept=employee, salary=2000.0, subordinates=[]]
Employee [name=员工1, dept=employee, salary=2000.0, subordinates=[]]
-------------------
Employee [name=刘老板, dept=headers, salary=23000.0, subordinates=[Employee [name=ceo小明, dept=ceo, salary=12000.0, subordinates=[Employee [name=组长, dept=groupLeader, salary=6000.0, subordinates=[Employee [name=员工1, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工2, dept=employee, salary=2000.0, subordinates=[]]]]]], Employee [name=ceo小红, dept=ceo, salary=12000.0, subordinates=[Employee [name=组长, dept=groupLeader, salary=6000.0, subordinates=[Employee [name=员工3, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工4, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工5, dept=employee, salary=2000.0, subordinates=[]]]]]]]]
Employee [name=ceo小明, dept=ceo, salary=12000.0, subordinates=[Employee [name=组长, dept=groupLeader, salary=6000.0, subordinates=[Employee [name=员工1, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工2, dept=employee, salary=2000.0, subordinates=[]]]]]]
Employee [name=组长, dept=groupLeader, salary=6000.0, subordinates=[Employee [name=员工1, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工2, dept=employee, salary=2000.0, subordinates=[]]]]
Employee [name=员工1, dept=employee, salary=2000.0, subordinates=[]]
Employee [name=员工2, dept=employee, salary=2000.0, subordinates=[]]
Employee [name=ceo小红, dept=ceo, salary=12000.0, subordinates=[Employee [name=组长, dept=groupLeader, salary=6000.0, subordinates=[Employee [name=员工3, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工4, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工5, dept=employee, salary=2000.0, subordinates=[]]]]]]
Employee [name=组长, dept=groupLeader, salary=6000.0, subordinates=[Employee [name=员工3, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工4, dept=employee, salary=2000.0, subordinates=[]], Employee [name=员工5, dept=employee, salary=2000.0, subordinates=[]]]]
Employee [name=员工3, dept=employee, salary=2000.0, subordinates=[]]
Employee [name=员工4, dept=employee, salary=2000.0, subordinates=[]]
Employee [name=员工5, dept=employee, salary=2000.0, subordinates=[]]
3. 总结
组合模式在类中使用一个列表或其他数据结构来存储其下属对象(子节点),类似于树,用来明了的表示对象之间的层次结构。