组合模式——七种结构型模式之一

1.前言

组合是一种整体与部分的关系,即对象与其内部对象之间的关系。通过之前的外观模式,体会到对象内部是可以很复杂的。最常见的情况便是,一个对象由多个对象组合而成,而部分参与组合的对象又是由多个对象组合而成,很像是树状结构。

这种结构的对象该如何访问呢?作为开发人员肯定想忽略掉这些区别,以一种统一的方式来处理每个对象。

2.概念

组合模式将对象组合成树形结构以表示“整体-部分”的层次结构,使得用户对组合对象和单个对象的使用具有一致性。这种统一的风格便是抽象的体现,需通过抽象类或接口来定义,由各种对象去实现。

这种模式特别适合模块化的结构,即层级结构明显,功能划分细致,像公司的组织架构,又或者计算机的文件系统。

3.场景

一个大的集团公司通常都是由许多子公司组成,每个子公司都有自己的业务范围。但只要是公司,必然有不同的部门,每个部门都有自己的工作目标。只不过,总公司统筹所有子公司而已。

4.写法

// 1.定义访问所有对象的共有接口
public abstract class Function {

    protected String name;

    // 2.实现缺省行为
    public Function(String name) {
        this.name = name;
    }

    public abstract void work();
}
// 1.实现组合对象及共有行为
public class Company extends Function {

    private List<Function> mFunctions = new ArrayList<>();

    public Company(String name) {
        super(name);
    }

    @Override
    public void work() {
        System.out.println("公司名为 " + name);
        if (mFunctions != null && !mFunctions.isEmpty()) {
            for (Function function : mFunctions) {
                function.work();
            }
        }
    }

    // 2.组合对象的特有行为
    public void addFunction(Function function) {
        mFunctions.add(function);
    }

    public void removeFunction(Function function) {
        mFunctions.remove(function);
    }

    public Function getFunction(int index) {
        return mFunctions.get(index);
    }
}
// 1.实现单个对象及共有行为
public class Department extends Function {
    public Department(String name) {
        super(name);
    }

    @Override
    public void work() {
        System.out.println("部门名为 " + name);
    }

    // 2.可添加单个对象的特有行为
}
public class Client {
    public static void main(String[] args) {
        // 1.构造集团公司
        Company group = new Company("XXX集团");

        Company company = new Company("XXX公司");
        Department onlineShopping = new Department("网络购物事业部");
        Department mobile = new Department("移动事业部");

        group.addFunction(company);
        group.addFunction(onlineShopping);
        group.addFunction(mobile);

        // 2.构造子公司
        Company subcompany = new Company("XXX子公司");
        Department localLife = new Department("本地生活事业部");
        Department cloud = new Department("云产品事业部");

        company.addFunction(subcompany);
        company.addFunction(localLife);
        company.addFunction(cloud);

        group.work();
    }
}

通过上面的代码,细心的朋友肯定会发现一个问题,那就是违背了依赖倒置原则。在Client类中直接使用Function的具体实现类,增加了代码间的耦合度,还忽视了Function的抽象作用。目前主流的开发方式就是面向接口编程,除了把焦点放在接口的设计外,还应注重接口的使用。

Function类无法使用,关键是因为只声明了公司和部门的共有方法,在实现类中才添加特有方法,对调用者屏蔽了具体实现的细节,这是安全的组合模式。若希望Function类得到使用,可以让其包括所有特有方法的声明,对外公开完整的访问结构,称为透明的组合模式

public abstract class Function {

    protected String name;

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

    public abstract void work();

    // 添加Company特有方法的声明
    public abstract void addFunction(Function function);

    public abstract void removeFunction(Function function);

    public abstract Function getFunction(int index);
}
public class Department extends Function {
    public Department(String name) {
        super(name);
    }

    @Override
    public void work() {
        System.out.println("部门名为 " + name);
    }

    // 1.实现Company特有方法
    @Override
    public void addFunction(Function function) {
        throw new UnsupportedOperationException("No function");
    }

    @Override
    public void removeFunction(Function function) {
        throw new UnsupportedOperationException("No function");
    }

    @Override
    public Function getFunction(int index) {
        throw new UnsupportedOperationException("No function");
    }

    // 2.可添加单个对象的特有行为
}

5.总结

在实际开发中,尤其是安卓开发,SDK提供的UI组件架构设计就是使用组合模式。大家可以回顾一下,TextView和ViewGroup继承自View,而共有方法包括了onMeasure()onLayout()onDraw()等。之所以这样,除了看中组合模式便于访问结构树中的节点外,还利于增删节点,为树形结构的面向对象实现提供灵活的解决方案。

    原文作者:lanceJin
    原文地址: https://www.jianshu.com/p/a4b78a7158b1
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞