设计模式——组合模式

195 阅读4分钟

一、概述

组合模式就是将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性,所以组合模式也可以叫做部分整体模式,它是一种结构型模式。就是用树状结构来表示部分和整体,使他们具有一致性,一致性的意思就是都实现了相同的接口或者继承了相同的父类。

举个具体的例子,总公司下面有多个部门,比如有研发部、产品部、运营部等部门,但是下属有其他的分公司,每个分公司可能负责不同的业务,也分别都有研发部、产品部以及运营部等部门;甚至在细分点,每个分公司下面还有子公司等等......

下面我们就以公司架构来用代码说明。

二、使用

首先创建一个公司的抽象接口,所有的具体公司和部门都要实现此接口。

public interface Company {

    String TAG = "XXX";

    //添加子公司
    void addCompany(Company company);

    //移除子公司
    void removeCompany(Company company);

    //展示所有子公司
    void displayAllCompany(int length);

    //公司职能
    void function();
}

再来定义具体的公司树枝节点。

/**
 * 具体的公司——树枝节点
 */
public class ConcreteCompany implements Company {

    //公司列表
    private List<Company> companyList = new ArrayList<>();
    //公司名称
    private String name;

    public ConcreteCompany(String name){
        this.name = name;
    }

    @Override
    public void addCompany(Company company) {
        companyList.add(company);
    }

    @Override
    public void removeCompany(Company company) {
        companyList.remove(company);
    }

    @Override
    public void displayAllCompany(int length) {
        StringBuilder builder = new StringBuilder();
        builder.append("-");
        for(int i=0;i<length;i++){
            builder.append("-");
        }
        builder.append(name);
        Log.e(TAG, builder.toString());
        for(Company company : companyList){
            company.displayAllCompany(length + 2);
        }
    }

    @Override
    public void function() {
        for(Company company : companyList){
            company.function();
        }
    }
}

最后就是定义公司的各个部门叶子节点,就是具体到哪个部门了,比如研发、产品等部门。

/**
 * 总经办部门——叶子节点
 */
public class ManagerDepartment implements Company {

    private String name;

    public ManagerDepartment(String name){
        this.name = name;
    }

    @Override
    public void addCompany(Company company) {

    }

    @Override
    public void removeCompany(Company company) {

    }

    @Override
    public void displayAllCompany(int length) {
        StringBuilder builder = new StringBuilder();
        builder.append("-");
        for(int i=0;i<length;i++){
            builder.append("-");
        }
        builder.append(name);
        Log.e(TAG, builder.toString());
    }

    @Override
    public void function() {
        Log.e(TAG, name + ",负责管理所有部门以及子公司");
    }
}
/**
 * 财务部门——叶子节点
 */
public class FinanceDepartment implements Company {

    private String name;

    public FinanceDepartment(String name){
        this.name = name;
    }

    @Override
    public void addCompany(Company company) {

    }

    @Override
    public void removeCompany(Company company) {

    }

    @Override
    public void displayAllCompany(int length) {
        StringBuilder builder = new StringBuilder();
        builder.append("-");
        for(int i=0;i<length;i++){
            builder.append("-");
        }
        builder.append(name);
        Log.e(TAG, builder.toString());
    }

    @Override
    public void function() {
        Log.e(TAG, name + ",负责清算所有员工的工资和福利");
    }
}
/**
 * 研发部门——叶子节点
 */
public class DevelopmentDepartment implements Company {

    private String name;

    public DevelopmentDepartment(String name){
        this.name = name;
    }

    @Override
    public void addCompany(Company company) {

    }

    @Override
    public void removeCompany(Company company) {

    }

    @Override
    public void displayAllCompany(int length) {
        StringBuilder builder = new StringBuilder();
        builder.append("-");
        for(int i=0;i<length;i++){
            builder.append("-");
        }
        builder.append(name);
        Log.e(TAG, builder.toString());
    }

    @Override
    public void function() {
        Log.e(TAG, name + ",负责研发游戏");
    }
}
/**
 * 产品部门——叶子节点
 */
public class ProductDepartment implements Company {

    private String name;

    public ProductDepartment(String name){
        this.name = name;
    }

    @Override
    public void addCompany(Company company) {

    }

    @Override
    public void removeCompany(Company company) {

    }

    @Override
    public void displayAllCompany(int length) {
        StringBuilder builder = new StringBuilder();
        builder.append("-");
        for(int i=0;i<length;i++){
            builder.append("-");
        }
        builder.append(name);
        Log.e(TAG, builder.toString());
    }

    @Override
    public void function() {
        Log.e(TAG, name + ",负责策划游戏的需求");
    }
}
/**
 * 运营部门——叶子节点
 */
public class OperationDepartment implements Company {

    private String name;

    public OperationDepartment(String name){
        this.name = name;
    }

    @Override
    public void addCompany(Company company) {

    }

    @Override
    public void removeCompany(Company company) {

    }

    @Override
    public void displayAllCompany(int length) {
        StringBuilder builder = new StringBuilder();
        builder.append("-");
        for(int i=0;i<length;i++){
            builder.append("-");
        }
        builder.append(name);
        Log.e(TAG, builder.toString());
    }

    @Override
    public void function() {
        Log.e(TAG, name + ",负责运营游戏");
    }
}

进行测试,打印输出如下图所示。

//根节点
ConcreteCompany rootCompany = new ConcreteCompany("总公司");
rootCompany.addCompany(new ManagerDepartment("总公司总经办"));
rootCompany.addCompany(new FinanceDepartment("总公司财务部"));

//子节点1
ConcreteCompany concreteCompany1 = new ConcreteCompany("分公司1");
concreteCompany1.addCompany(new DevelopmentDepartment("分公司1研发部"));
concreteCompany1.addCompany(new ProductDepartment("分公司1产品部"));
rootCompany.addCompany(concreteCompany1);

//子节点2
ConcreteCompany concreteCompany2 = new ConcreteCompany("分公司2");
Company2.addCompany(new DevelopmentDepartment("分公司2研发部"));
concreteCompany2.addCompany(new ProductDepartment("分公司2产品部"));
concreteCompany2.addCompany(new OperationDepartment("分公司2运营部"));
rootCompany.addCompany(concreteCompany2);

rootCompany.displayAllCompany(1);
rootCompany.function();

三、总结

组合模式使得客户端可以一致的使用一个组合模式或对单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端的代码;在组合模式种增加新的容器组件和叶子组件都很方便,无需对现有类库进行任何修改,符合开闭原则。但是也可以看到很明显的缺点,在叶子节点中也实现了add()和remove()方法,因为这样叶子节点和其他节点对于外界没有区别,它们具有完全一致的行为接口,但是叶子节点的这2个方法时没有意义的,给客户端带来了不安全性,这种方式就是透明方式。

我们也可以在Company接口中不去定义这2个方法,这样安全性得到了提高,但是与此相对变得不再透明,树叶和树枝将不再具有相同的接口,客户端调用时就需要做相对应的判断。这时只需要将这两个方法移到ConcreteCompany类中去就行,具体的部门类中移除这两个方法,具体操作这里就不再过多说明,可以去尝试写出来。

github地址:github.com/leewell5717…

四、参考

java设计模式--组合模式