简述-组合模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ddxxii/article/details/84112256

介绍

本模式为结构型设计模式之一,也称为部分与整体模式。在上面说到解释器模式,里面有叶子和枝干到概念。本模式也有叶子和枝干到概念。将一组相似到对象看作一个对象处理,并根据一个树状架构来组合对象,提供一个统一的方法去访问相应的对象。总公司有子公司和其部门组成,子公司又有自己的部门,这里母公司就是根,母公司部门就是叶子,子公司就是枝干,子公司部门又是叶子。

比如:像我们文件和目录使用的则是组合模式。Android中View和ViewGroup则也是使用的组合模式。往下看下就明白了,组合模式这里谈到了两个概念:

  • 透明模式: 组合使用的方法都定义在抽象类
  • 安全模式: 组合使用的方法定义在自己内部

UML

透明模式

安全模式

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

安全模式中,由于枝干部分行为定义在枝干中,那么只有直接使用枝干来操作,这样违背了依赖导致原则,所有有了透明模式。透明模式是都用抽象对象来操作了,但是叶子节点多了自己不需要的方法。看情况自己指定

事例

就拿文件和目录来距离把,目录下面可以放文件也可以放目录,在访问的时候,就是一个树形结构,来咱们用组合模式撸一下。

咱们的目录结构如下:

  1. 创建抽象根节点:
/**
 * 抽象的根节点
 */
public abstract class AbsComposite {
    /**
     * 名称
     */
    protected String name;

    /**
     * 处理事
     */
    abstract void doSomeThis();

    /**
     * 是否是目录
     *
     * @return
     */
    abstract boolean isDictionary();
}

根节点提供处理方法和名称,是否是目录方法

  1. 创建文件节点:
/**
 * 文件实现,叶子节点
 * 1. 实现抽象方法:输出当前文件名字
 */
public class FileComposite extends AbsComposite {
    public FileComposite(String name) {
        this.name = name;
    }

    @Override
    void doSomeThis() {
        //文件的话就直接输出名字
        System.out.println("文件:" + name + ",是不是目录:" + isDictionary());

    }

    @Override
    boolean isDictionary() {
        //返回不是目录
        return false;
    }
}

文件节点,作为叶子节点,就只需要实现抽象方法即可

  1. 创建枝干节点:
/**
 * 目录,枝干节点
 * 1. 提供内部方法:添加、删除、获取
 * 2. 实现抽象放啊放: 返回是目录,遍历当前目录下节点
 */
public class DircComposite extends AbsComposite {
    /**
     * 目录下装的其他节点
     */
    private List<AbsComposite> absComposites = new ArrayList<>();

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

    @Override
    void doSomeThis() {
        //先输出当前目录名字
        System.out.println("目录:" + name + ",是不是目录:" + isDictionary());
        //遍历当前目录下的节点
        for (AbsComposite absComposite : absComposites) {
            absComposite.doSomeThis();
        }
    }

    @Override
    boolean isDictionary() {
        //返回是目录
        return true;
    }

    /**
     * 枝干内部方法,添加节点
     *
     * @param absComposite 节点
     */
    public void addComposite(AbsComposite absComposite) {
        absComposites.add(absComposite);
    }

    /**
     * 移除节点
     *
     * @param absComposite 节点
     */
    public void removeComposite(AbsComposite absComposite) {
        absComposites.remove(absComposite);
    }

    /**
     * 获取子节点列表
     *
     * @return 子节点列表
     */
    public List<AbsComposite> getChilds() {
        return absComposites;
    }
}

目录,枝干节点,除了实现抽象方法还需要有内部方法。

  1. 测试类:
//先创建要用的目录和文件
        DircComposite dicTop = new DircComposite("目录1");
        DircComposite dicSecond = new DircComposite("目录1中的目录2");
        DircComposite dicSecond1 = new DircComposite("目录2中的目录3");
        AbsComposite fileTop1 = new FileComposite("目录1中的文件1");
        AbsComposite fileTop2 = new FileComposite("目录1中的文件2");
        AbsComposite fileSecond1 = new FileComposite("目录2中的文件1");
        AbsComposite fileSecond2 = new FileComposite("目录2中的文件2");
        //将文件1和文件2放到目录1中
        dicTop.addComposite(fileTop1);
        dicTop.addComposite(fileTop2);
        //将目录2中文件1和目录2中文件2放到目录2中
        dicSecond.addComposite(fileSecond1);
        dicSecond.addComposite(fileSecond2);
        //目录3放到目录2中
        dicSecond.addComposite(dicSecond1);
        //将目录2放到目录1中
        dicTop.addComposite(dicSecond);
        //从顶层目录开始操作
        dicTop.doSomeThis();
  1. 输出:
目录:目录1,是不是目录:true
文件:目录1中的文件1,是不是目录:false
文件:目录1中的文件2,是不是目录:false
目录:目录1中的目录2,是不是目录:true
文件:目录2中的文件1,是不是目录:false
文件:目录2中的文件2,是不是目录:false
目录:目录2中的目录3,是不是目录:true

我想各位从上面能看出,这里用到的是安全组合模式,组合使用的内部方法是在枝干内部,没有定义到抽象类,当然造成的情况就是测试对象那里,只能显示的声明为DircComposite了。带来的好处就是对叶子的侵入小。

使用场景

  • 表示对象-部分整体层次结构时
  • 从一个整体中能够独立出部分模块或功能的场景

优缺点

优点:

  • 清除定义对象层次,高层模块忽略层次差异,方便对整个层次结构进行控制。
  • 高层模块可以一致性使用结构中对对象(迭代)。简化了高层模块代码。
  • 增加新对枝干或者叶子都比较方便,符合“开关闭原则”。
  • 为树形结构提供了灵活方案。

缺点

  • 牺牲了类的单一原则。
  • 新增构建不好对枝干中的构件类型进行限制,不能依赖类型系统来施加这些约束,因为一般都来自相同的抽象层,就需要进行类型检查来实现。

总结:其思想是将对象组合成树形结构,使得单个对象和组合对象的使用具有一致性,部分与整体的结构就出来了,通过继承方式,可以组合兼容,方便遍历等。

猜你喜欢

转载自blog.csdn.net/ddxxii/article/details/84112256