设计模式之 组合模式

组合模式(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 产品小李

类结构图: