组合模式(Composite Pattern),主要用在将一系列对象组织成树形结构,来表示部分和整体。
使用组合模式表示后,整体和部分的差异就被统一了,调用复杂对象就跟调用简单对象一样,两种对象不再需要区别对待。
我们以公司中的人员为例,比如公司按照职位不同,权限也不相同。
如果是普通员工,就是上班工作,如果是领导,则可以往自己的部门添加人员或删除人员,我们传统的做法可能是员工一个类,类中写员工各种角色所支持的业务逻辑;而领导角色也写一个类,其中都是领导角色所能行使的权利。
但是如果公司的角色特别多,那是不是要写很多不同功能的员工类了,但是这其实都是员工,只是因为职位的不同,行使的权利又所差异。
那么我们现在就看看,使用组合模式的效果。
1、定义抽象员工类,将公共部分抽象到这里
package com.itzhimei.study.design.composite;
/**
* @Auther: www.itzhimei.com
* @Description: 员工抽象类 定义员工基本属性和功能
*/
public abstract class Staff {
private String no;
private String name;
public Staff(String no, String name) {
this.no = no;
this.name = name;
}
public void printInfo() {
System.out.println(" "+ this.no + " " + this.name);
}
public abstract void add(Staff staff);
public abstract Boolean remove(String no);
public abstract void printEmployeeInfo(int level);
public void printLevelChar(int level) {
for(int i=0; i<level; i++) {
System.out.print("--");
}
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2、定义管理者角色类
package com.itzhimei.study.design.composite;
import java.util.ArrayList;
import java.util.List;
/**
* @Auther: www.itzhimei.com
* @Description: 管理者
*/
public class Manager extends Staff {
private List<Staff> list = new ArrayList<>();
public Manager(String no, String name) {
super(no, name);
}
@Override
public void add(Staff staff) {
//加定员工编号不会重复,这里不做处理
this.list.add(staff);
}
@Override
public Boolean remove(String no) {
Staff staff = null;
return this.list.removeIf(x->x.getNo().equals(no));
}
@Override
public void printEmployeeInfo(int level) {
int nextLevel = ++level;
for(int i=0; i<this.list.size(); i++) {
this.list.get(i).printLevelChar(level);
this.list.get(i).printInfo();
this.list.get(i).printEmployeeInfo(nextLevel);
}
}
}
管理者中有具体的添加、删除员工,并且能打印其下属的完整信息,并且是以树形结果输出额。
3、定义普通员工角色
package com.itzhimei.study.design.composite;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public class Employee extends Staff {
public Employee(String no, String name) {
super(no, name);
}
@Override
public void add(Staff staff) {
return;
}
@Override
public Boolean remove(String no) {
return false;
}
@Override
public void printEmployeeInfo(int level) {
return;
}
}
从普通员工角色中,可以看到,从父类继承的添加、删除员工,打印员工信息方法,都是实现了空方法,这样让两种类的表现是一致的,外部在调用时,不必区分差异,而是调用的同一种类型的对象。
4、测试
package com.itzhimei.study.design.composite;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public class Client {
public static void main(String[] args) {
Staff ceo = new Manager("1","CEO张");
//总经理
Staff gm = new Manager("2","generalManager王");
//开发总监
Staff cdo = new Manager("3","CDO李");
//产品总监
Staff pd= new Manager("4","PD徐");
Staff softwareEngineer1= new Employee("5","开发小明");
Staff softwareEngineer2= new Employee("6","开发小李");
Staff softwareEngineer3= new Employee("7","开发小张");
Staff productEngineer1= new Employee("8","产品小东");
Staff productEngineer2= new Employee("9","产品小李");
ceo.add(gm);
gm.add(cdo);
gm.add(pd);
cdo.add(softwareEngineer1);
cdo.add(softwareEngineer2);
cdo.add(softwareEngineer3);
pd.add(productEngineer1);
pd.add(productEngineer2);
ceo.printInfo();
ceo.printEmployeeInfo(1);
}
}
我们定义了一些列公司人员,并绑定了人员所属上级。
输出
1 CEO张
---- 2 generalManager王
------ 3 CDO李
-------- 5 开发小明
-------- 6 开发小李
-------- 7 开发小张
------ 4 PD徐
-------- 8 产品小东
-------- 9 产品小李
类结构图: