【设计模式】组合模式

组合模式

计算机的文件系统中,一个文件夹中既可以放入文件也可以放入其他文件夹(子文件夹),所以文件夹和文件虽然是不同类型的对象,但它们都是可以被放入到文件夹中,可以统称为"目录条目"(directory entry)
在目录条目中,我们把文件夹和文件当作同一对象看待。
将容器和内容作为同一种东西看待,在容器中既可以放入内容,也可以放入小容器,然后在那个小容器中,又可以继续放入更小的容器,这样就形成一种容器的递归结构(有点类似于俄罗斯套娃的感觉)

在 GoF 的《设计模式》⼀书中,组合模式是这样定义的:

Compose objects into tree structure to represent part-whole hierarchies.Composite lets client treat individual objects and compositions of objects uniformly.

Composite模式就是创造出使容器与内容具有一致性的递归结构的模式。它将对象组合成树型结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的操作具有一致性,主要是⽤来处理树形结构数据,属于结构型模式。

组合模式模板

组合模式通常包含三种角色 :

  1. Component:抽象根节点,为Composite和Leaf声明接口,是所有节点的上层父类,可以为一些功能方法定义缺省的实现
  2. Leaf 叶子节点, 其下不再包含其他的子节点对象
  3. Composite 树枝节点 通常会包含子节点,组合的树枝节点和子节点形成一个树形结构

组合模式模板类图

其模板如下:

public abstract  class  Component {
    protected  abstract void doSomeOperation();
    /**
     * 向组合对象中加入组件对象
     * 叶子对象没有该功能
     *
     * */
    protected  void addChild(Component component) {
        throw new UnsupportedOperationException("此对象不支持addChild该功能");
    }
    /**
     * 向组合对象中移除组件对象
     * 叶子对象没有该功能
     *
     * */
    protected  void removeChild(Component component){
        throw new UnsupportedOperationException("此对象不支持removeChild该功能");
    }
}

public class Leaf extends  Component {
    protected void doSomeOperation() {
        //TODO
    }

}
public class Composite extends  Component {
    private List<Component> componentList = null;
    protected void doSomeOperation() {
        //TODO
    }

    @Override
    protected void addChild(Component component) {
        if(componentList == null){
            componentList = new ArrayList<Component>();
        }
        componentList.add(component);
    }

    @Override
    protected void removeChild(Component component) {
        if(componentList != null){
            componentList.remove(component);
        }
    }
}

这是组合模式的模板类图:树枝节点/子节点的方法可以根据实际情况来定义

透明组合模式代码示例

在一个商品管理的系统里,我们需要打印一个商品树的树型结构,如下图:
商品树--服装

可以将这里的节点分成两类:一种是没有子节点的叶子节点:夹克,衬衫等 ; 一种是有子节点的树枝节点:服务,女装等。
我们为其定义一个抽象父类,这样叶子节点和容器节点既能保证一致性,又可以有各自不同的实现

public abstract  class  Component {

    private String name = "";

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

    protected String getName(){
        return name;
    }

    protected  abstract void printStruct(String prefix);
    /**
     * 向组合对象中加入组件对象
     * 叶子对象没有该功能
     *
     * */
    protected  void addChild(Component component) {
        throw new UnsupportedOperationException("此对象不支持addChild该功能");
    }
    /**
     * 向组合对象中移除组件对象
     * 叶子对象没有该功能
     *
     * */
    protected  void removeChild(Component component){
        throw new UnsupportedOperationException("此对象不支持removeChild该功能");
    }
}

public class Leaf extends Component {

    public Leaf(String name){
        super(name);
    }
    /***
     * 打印对应的叶子结构
     * @param  prefix 前缀 实现向后缩进
     *
     */
    public void printStruct(String prefix){
        System.out.println(prefix + "-" + super.getName());
    }
}

public class Composite extends Component{

    List<Component> componentList = new ArrayList<>();

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

    @Override
    protected void printStruct(String prefix) {
        System.out.println(prefix + "+"  + getName());
        if (componentList != null) {
            //打印其叶子节点,缩进一个空格
            for(Component component: componentList) {
                component.printStruct(prefix + prefix);
            }
        }
    }

    @Override
    protected void addChild(Component component) {
        this.componentList.add(component);
    }

    @Override
    protected void removeChild(Component component) {
        this.componentList.remove(component);
    }
}

public class Client {
    public static void main(String[] args) {
        //组合对象  作为根节点
        Component root  = new Composite("服装");
        //组合对象
        Component composite1 = new Composite("夏装");
        Component composite2 = new Composite("冬装");
        //叶子节点
        Leaf leaf1 = new Leaf("裙子");
        Leaf leaf2 = new Leaf("背心");
        Leaf leaf3 = new Leaf("棉衣");

        root.addChild(composite1);
        root.addChild(composite2);

        composite1.addChild(leaf1);
        composite1.addChild(leaf2);
        composite2.addChild(leaf3);

        root.printStruct("");

    }
}

输出结果:
在这里插入图片描述

组合模式的安全性和透明性

组合模式中,Composite对象就像是一个容器,可以包含其他的树枝节点或者叶子节点。作为一个容器, 我们可以向其中添加或者删除子节点(包括Leaf和Composite节点)

这样在使用组合模式的时候就需要考虑对叶子节点的操作是在Component还是Composite中声明?这就是对安全性和透明性之前的权衡。

安全性 : 从用户使用角度上组合模式是否安全,如果是安全的,那么用户在使用的时候就不会有发生误操作的可能性,能访问的都是支持的有意义的操作

透明性 : 用户使用组件对象的时候是否需要区分到底是容器对象还是叶子对象, 如果是透明的,就不需要区分 (上面的写法其实就是透明组合模式的写法)

透明性的实现:将操作子节点的方法定义在Component, 同时为了兼顾安全性,可以在Component中为这些方法提供默认实现 比方说抛出异常,默认的空实现或者定义成抽象方法。不过这也违背了设计的单一原则

安全性的实现: 把操作子节点的方法定义在Composite

透明组合模式将所有的接口都定义在抽象根节点里,当叶子节点和树枝节点绝大多数情形下都具备相同的行为时,使用透明组合模式更加方便;而如果不同层次的节点的行为差异较大,更推荐安全组合模式的写法。

组合模式在源码中的应用

HashMap里就使用到了组合模式

  public static void main(String[] args) {
        Map<String, String> root = new HashMap<>();
        map.put("0", "Xiaoming");
        Map<String, String> map = new HashMap<>();
        map.put("1", "Tom");
        map.put("2", "Alice");
        root.putAll(map);

    }

在这里插入图片描述
这里的Map是一个抽象根节点,HashMap是一个树枝节点,Node是叶子节点
HashMap中存储的就是一个静态内部类的数组 bashNode<K,V>[] tab

ArrayList也类似,Collection是其抽象根节点,ArrayList是树枝节点,叶子节点是 Object

总结

组合模式,将⼀组对象组织成树形结构,将单个对象和组合对象都看做树中的节点,以统⼀处理逻辑,并且它利⽤树形结构的特点,递归地处理每个⼦树,依次简化代码实现。使⽤组合模式的前提在于,你的业务场景必须能够表⽰成树形结构。

优点

  1. 定义了基本对象和组合对象的类层次结构
  2. 统一了组合对象和叶子对象,简化了客户端的调用

缺点 : 很难限制组合中的节点类型

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
本电子书一共两个压缩文档,本文件为part2. 《研磨设计模式》完整覆盖GoF讲述的23个设计模式并加以细细研磨。初级内容从基本讲起,包括每个模式的定义、功能、思路、结构、基本实现、运行调用顺序、基本应用示例等,让读者能系统、完整、准确地掌握每个模式,培养正确的“设计观”;高级内容则深入探讨如何理解这些模式,包括模式蕴涵什么样的设计思想,模式的本质是什么,模式如何结合实际应用,模式的优缺点以及与其他模式的关系等,以期让读者尽量去理解和掌握每个设计模式的精髓所在。    《研磨设计模式》在内容上深入、技术上实用、和实际开发结合程度很高,书大部分的示例程序都是从实际项目简化而来,因此很多例子都可以直接拿到实际项目使用。如果你想要深入透彻地理解和掌握设计模式,并期望能真正把设计模式应用到项目去,那么这是你不可错过的一本好书。    《研磨设计模式》难度为初级到级,适合与所有开发人员、设计人员或者即将成为开发人员的朋友。也可以作为高效学生深入学习设计模式的参考读物! 第1章 设计模式基础    第2章 简单工厂    第3章 外观模式    第4章 适配器模式(Adapter)    第5章 单例模式(Singleton)    第6章 工厂方法模式(Factory Method)    第7章 抽象工厂模式(Abstract Factory)    第8章 生成器模式(Builder)    第9章 原型模式(Prototype)    第10章 介者模式(Mediator)    第11章 代理模式(Proxy)    第12章 观察者模式(Observer)    第13章 命令模式(Command)    第14章 迭代器模式(Iterator)    第15章 组合模式(Composite)    第16章 模板方法模式(Template Method)    第17章 策略模式(Strategy)    第18章 状态模式(State)    第19章 备忘录模式(Memento)    第20章 享元模式(Flyweight)    第21章 解释器模式(Interpreter)    第22章 装饰模式(Decorator)    第23章 职责链模式(Chain of Responsibility)    第24章 桥接模式(Bridge)    第25章 访问者模式(Visitor)    附录A常见面向对象设计原则    附录BUML简介    参考文献
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值