深入理解设计模式-组合模式

Posted 、Dong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入理解设计模式-组合模式相关的知识,希望对你有一定的参考价值。

文章目录


一、定义

组合模式允许我们将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。


二、使用场景

组合模式正是应树形结构而生,所以组合模式的使用场景就是出现树形结构的地方。比如:文件目录显示,多级目录呈现等树形结构数据的操作。


三、代码样例

1.类图

通过组合模式,构建一颗树,打印所有节点

2.抽象类

/**
 * Component为组合中的对象声明接口,在适当情况下,实现所有类共有接口的默认行为。
 */
public abstract class Component 
    protected String name;

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

    public abstract void add(Component component);

    public abstract void remove(Component component);

    public abstract void display(int depth);


3.具体实现类

/**
 * 定义有枝节点行为,用来存储子部件
 */
public class Composite extends Component 
    private List<Component> children = new ArrayList<Component>();

    public Composite(String name) 
        super(name);
    

    @Override
    public void add(Component component) 
        children.add(component);
    

    @Override
    public void remove(Component component) 
        children.remove(component);
    

    @Override
    public void display(int depth) 
        // 显示其枝节点名称,并对其下级进行遍历
        System.out.println(StringUtils.repeat("-", depth) + this.name);

        for (Component component : children) 
            component.display(depth + 2);
        
    

/**
 * Leaf在组合中表示叶节点对象,叶节点没有子节点
 */
public class Leaf extends Component 

    public Leaf(String name) 
        super(name);
    

    @Override
    public void add(Component component) 
        System.out.println("cannot add to a leaf");
    

    @Override
    public void remove(Component component) 
        System.out.println("cannot remove from a leaf");
    

    @Override
    public void display(int depth) 
        // 通过“-”的数目显示级别
        System.out.println(StringUtils.repeat("-", depth) + this.name);
    


4.客户端类

/**
 * 客户端。通过Component接口操作组合部件的对象
 */
public class CompositeClient 

    public static void main(String[] args) 
        // 生成树根,根上长出两叶Leaf A和Leaf B
        Composite root = new Composite("root");
        root.add(new Leaf("Leaf A"));
        root.add(new Leaf("Leaf B"));

        // 根上长出分支Composite X,分支上也有两叶Leaf X-A和Leaf X-B
        Composite compositeX = new Composite("Composite X");
        compositeX.add(new Leaf("Leaf X-A"));
        compositeX.add(new Leaf("Leaf X-B"));
        root.add(compositeX);

        // 在Composite X上再长出分支Composite X-Y,分支上也有两叶Leaf X-Y-A和Leaf X-Y-B
        Composite compositeXY = new Composite("Composite X-Y");
        compositeXY.add(new Leaf("Leaf X-Y-A"));
        compositeXY.add(new Leaf("Leaf X-Y-B"));
        compositeX.add(compositeXY);

        // 显示大树的样子
        root.display(1);
    

5.输出


四、优缺点

优点:

  • 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。
  • 在组合模式中增加新的树枝节点和叶子节点都很方便,无须对现有类库进行任何修改,符合“开闭原则”。
  • 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子节点和树枝节点的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。

缺点:

  • 在增加新构件时很难对容器中的构件类型进行限制。有时候我们希望一个容器中只能有某些特定类型的对象,例如在某个文件夹中只能包含文本文件,使用组合模式时,不能依赖类型系统来施加这些约束,因为它们都来自于相同的抽象层

五、模式分类

透明组合模式:
透明组合模式中,抽象根节点角色中声明了所有用于管理成员对象的方法,比如在示例中 Component 声明了 add、remove方法,这样做的好处是确保所有的构件类都有相同的接口。透明组合模式也是组合模式的标准形式。

透明组合模式的缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的,因此为其提供 add、remove 等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用这些方法可能会出错

安全组合模式:
在安全组合模式中,在抽象构件角色中没有声明任何用于管理成员对象的方法,而是在树枝节点 Menu 类中声明并实现这些方法。安全组合模式的缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件。


结尾

  • 感谢大家的耐心阅读,如有建议请私信或评论留言。
  • 如有收获,劳烦支持,关注、点赞、评论、收藏均可,博主会经常更新,与大家共同进步
创作打卡挑战赛 赢取流量/现金/CSDN周边激励大奖

以上是关于深入理解设计模式-组合模式的主要内容,如果未能解决你的问题,请参考以下文章

深入理解设计模式-组合模式

设计模式 结构型模式 -- 组合模式

深入理解JavaScript系列(40):设计模式之组合模式

设计模式-结构型-7-组合模式

组合模式(18)

Java 设计模式之组合学习与掌握