浅学设计模式之组合模式(17/23)

1. 组合模式的概念

组合模式(Composite), 将对象组合成属性结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

组合模式也被成为 部分-整体模式,属于结构型的设计模式。
组合模式比较简单,它将一组相似的对象看做一个对象来处理,并根据一个树状结构来组合对象,然后提供一个统一的方法去访问相应的对象,以此忽略掉对象与对象集合之间的差别。

生活中一个比较典型的例子就是公司的组织结构树状图,如下所示:
在这里插入图片描述
上面是一个公司的组织结构树状图,其中总公司下有人力资源部与财务部,而且总公司下属还有一个分公司,分公司有自己的人力部和财务部,对于总公司来说,子公司就是一个独立的个体,与总公司所属的人力部和财务部是平级的。

糟糕的使用
当我们在构建后台系统时,如果我们要让上图中所有的部门都复用同一套代码,这个时候就会产生因为大量的判断语句,我首先要判断是否为总公司的人力部、再判断是否为总公司的财务部、再判断是否为子公司的人力部、再判断是否为子公司的财务部,当部门一多或或者共用的代码一多,就会显得十分臃肿,产生了非常糟糕的代码。

抽象结构
在这么一个结构中,大家可以看到,虽然总公司和子公司本质不一样,但是它在我们的组织结构中是一样的,我们可以把他们看做是一个抽象的公司,在组合模式中我们将这样一个拥有分支的节点成为枝干构件,位于树状结构顶部的枝干结构比较特殊,我们成为根结构件,因为其为整个树状图的始端,同样对于像人力部和财务部这样没有分支的结构,我们则成为 叶子构件,这样的结构就是组合模式的雏形:

在这里插入图片描述

2. UML图

来看下组合模式的UML类图:
在这里插入图片描述

它有这么几个成员角色:

  • Component,抽象根节点
    为组合中的对象声明接口。在适当的情况下,实现所有类共有接口的缺省行为。
    声明一个接口用于访问和管理Component的子节点。可在递归结构中定义一个接口,用于访问一个父节点,并在合适的情况下实现它
  • Composite
    定义有子节点的那些枝干节点的行为,存储子节点,在Component接口中实现与子节点有关的操作
  • Leaf
    在组合中表示叶子节点对象,叶子节点没有子节点,在组合中定义节点的对象行为

下面展示一下模板代码,
先来看下抽象根节点:

public abstract class Component {
    // 节点名
    protected String name;

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

    /**
     * 具体的逻辑方法由子类实现
     */
    public abstract void doSomething();
}

来看下具体实现抽象根节点的具体枝干节点:

public class Composite extends Component {
    /**
     * 存储节点的容器
     */
    private List<Component> components = new ArrayList<>();

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

    @Override
    public void doSomething() {
        System.out.println(name);
        if (components != null) {
            for (Component c : components) {
                c.doSomething();
            }
        }
    }

    /**
     * 添加子节点
     *
     * @param child
     */
    public void addChild(Component child) {
        components.add(child);
    }

    /**
     * 移除子节点
     *
     * @param child
     */
    public void removeChild(Component child) {
        components.remove(child);
    }

    /**
     * 获取子节点 根据对应的下标
     *
     * @param index
     * @return
     */
    public Component getChildren(int index) {
        return components.get(index);
    }
}

接下来是叶子节点,它也继承了Component类:

public class Leaf extends Component {
    public Leaf(String name) {
        super(name);
    }

    @Override
    public void doSomething() {
        System.out.println(name);
    }
}

最后来看下客户端类是如何应用组合模式的:

class CompositeMain {
    public static void main(String[] args) {
        // 构造一个根节点
        Composite root = new Composite("Root");

        // 构造两个枝干节点
        Composite branch1 = new Composite("Branch1");
        Composite branch2 = new Composite("Branch2");

        // 构造两个叶子节点
        Leaf leaf1 = new Leaf("Leaf1");
        Leaf leaf2 = new Leaf("Leaf2");

        //将叶子节点添加至枝干节点中
        branch1.addChild(leaf1);
        branch2.addChild(leaf2);

        //将枝干节点添加到跟节点中
        root.addChild(branch1);
        root.addChild(branch2);

        //执行方法
        root.doSomething();
    }
}

3. 组合模式在Android中应用

在Android中,组合模式是有非常经典的应用的,而且天天都会用到,那就是View和ViewGroup的嵌套组合

我们来看下View和ViewGroup的关系:
在这里插入图片描述
这里省略了View和ViewGroup类中的一些方法,在Android的这个视图层级中,容器一定是ViewGroup,而且只有ViewGroup才能包含其他的View,比如 LinearLayout能包含TextView、Button、CheckBox等,但是反过来TextView是不能包含LinearLayout的,因为TextView直接继承与View,其并非一个容器。这里View的视图层级中使用到的其实是一种安全的设计模式。

具体的源码这里就不做分析了。

4. 小结

组合模式的使用场景:

  • 表示对象可以形成部分-整体层次结构时。
  • 从一个整体中能够独立处部分模块或功能的场景(显然,View这个模块能够独立出ViewGroup这个模块出来)

组合模式让客户可以一致地使用组合结构和单个对象。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值