一、组合模式的介绍
1、定义
组合模式将对象组合成树形结构以表示“整体-部分”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。组合模式在我们生活中是十分常见的,例如机构的划分。
组合模式用于将多个对象组合成树形结构以表示“整体-部分”的结构层次,组合模式对单个对象(叶子对象)和组合对象(容器对象)的使用具有一致性。组合模式的关键在于它定义了一个抽象构件类,它既可以表示叶子对象,也可以表示容器对象,客户仅仅需要针对这个抽象构件进行编程,无需知道它是叶子对象还是容器对象,都是一致对待(一碗水平端)。
组合模式中的角色划分:
- 抽象构件角色(Component):该角色定义参加组合对象的共有方法和属性,规范一些默认的行为接口。
- 叶子构件角色(Leaf):该角色是叶子对象,其下没有其他的分支,定义出参加组合的原始对象的行为。
- 树枝构建角色(Composite):该角色代表参加组合的、其下有分支的树枝对象,它的作用是将树枝和叶子组合成一个树形结构,并定义出管理子对象的方法,如:add()、remove()等。
组合模式的类图如下:
![](https://i-blog.csdnimg.cn/blog_migrate/cf96e7cdabf7f31e6d5c57ac3035eb06.png)
2、使用场景
- 需要描述对象的部分和整体的等级结构,如:树形菜单、文件和文件夹管理。
- 需要客户端忽略个体构件和组合构件的区别,平等对待所有的构件。
3、优缺点
(1)优点
- 可以清楚地定义分层次的复杂对象,表示对象的全部或者部分层次,从而让增加新的构件也更为容易。
- 客户端调用简单,客户端可以一致的使用组合结构或者其中的单个对象。
- 定义了包含叶子对象和容器对象的类层次结构,叶子对象可以被组合成更为复杂的容器对象,而这个容器对象又可以被组合,这样不断地跪下去,可以形成复杂的树形结构。
- 更容易在组合体中加入对象构件,客户端不必因为加入了新的对象构件而更改原有代码。
(2)缺点
- 不易控制树枝构件的类型。
- 不易使用继承的方法来增加新的行为。
二、组合模式的实现
场景描述:现实生活中,类似于组合模式的例子很多,这里就用组合模式来实现公司的机构划分。类图如下:
抽象构件角色:
/**
* 抽象构件角色
*/
public interface Company {
String getInfo();
}
叶子构件角色:
public class Employee implements Company{
private String name;
private String position;
private Double salary;
public Employee(String name, String position, Double salary) {
this.name = name;
this.position = position;
this.salary = salary;
}
@Override
public String getInfo() {
return "姓名:" + this.name + "\t" + "职位:" + this.position + "\t" + "薪资:" + this.salary;
}
}
树枝构件角色:
public class ConcreteCompany implements Company{
private String name;
private String position;
private Double salary;
private List<Company> companyList = new ArrayList<>();
public ConcreteCompany(String name, String position, Double salary) {
this.name = name;
this.position = position;
this.salary = salary;
}
public void add(Company company){
this.companyList.add(company);
}
public void remove(Company company){
this.companyList.remove(company);
}
public List<Company> getChild(){
return this.companyList;
}
@Override
public String getInfo() {
return "姓名:" + this.name + "\t" + "职位:" + this.position + "\t" + "薪资:" + this.salary;
}
}
测试:
public class Client {
public static void main(String[] args) {
ConcreteCompany root = new ConcreteCompany("张老大", "董事长", 50000.0);
ConcreteCompany developDep = new ConcreteCompany("李方", "研发部经理", 30000.0);
ConcreteCompany saleDep = new ConcreteCompany("孙怛", "销售部经理", 30000.0);
ConcreteCompany financeDep = new ConcreteCompany("刘华", "财务部经理", 30000.0);
Employee e1 = new Employee("A", "研发部", 5500.0);
Employee e2 = new Employee("B", "研发部", 5500.0);
Employee e3 = new Employee("C", "研发部", 5500.0);
Employee e4 = new Employee("D", "研发部", 5500.0);
Employee e5 = new Employee("E", "销售部", 5500.0);
Employee e6 = new Employee("F", "销售部", 4000.0);
Employee e7 = new Employee("G", "销售部", 4000.0);
Employee e8 = new Employee("H", "财务部", 3000.0);
Employee e9 = new Employee("I", "财务部", 3000.0);
Employee e10 = new Employee("J", "研发部",5500.0 );
root.add(developDep);
root.add(saleDep);
root.add(financeDep);
developDep.add(e1);
developDep.add(e2);
developDep.add(e3);
developDep.add(e4);
developDep.add(e10);
saleDep.add(e5);
saleDep.add(e6);
saleDep.add(e7);
financeDep.add(e8);
financeDep.add(e9);
System.out.println(root.getInfo());
display(root);
}
public static void display(ConcreteCompany root){
for(Company c : root.getChild()){
if(c instanceof Employee){
System.out.println(c.getInfo());
}else{
System.out.println("\n" + c.getInfo());
display((ConcreteCompany) c);
}
}
}
}