设计模式:组合模式(Composite)

将对象组合成属性结构以表示“部分-总体”的层次结构。组合使得用户和单个对象和组合对象的使用具有一致性。

组合模式设计的角色:

1. Component:是组合中的对象声明接口。在适当的情况下。实现全部类共同拥有接口的默认行为。声明一个接口用于訪问和管理Component.

2. Leaf:在组合中表示叶子节点对象。叶子节点没有子节点。

3. Composite:定义树枝节点行为。用来存储子部件。在Component接口中实现与子部件有关操作,如增加和删除等。

举个简单样例(树枝和叶子)

1 Component

public abstract class Component
{
    protected String name;

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

    protected abstract void add(Component component);
    protected abstract void remove(Component component);
    protected abstract void operation(int depth);
    protected abstract List<Component> getChildren();
}

2 Leaf(树叶)

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

    @Deprecated
    public void add(Component component) throws UnsupportedOperationException
    {
        throw new UnsupportedOperationException();
    }

    @Deprecated
    public void remove(Component component) throws UnsupportedOperationException
    {
        throw new UnsupportedOperationException();
    }

    @Override
    protected void operation(int depth){
        String temp = "";
        for(int i=0;i<depth;i++)
        {
            temp += "    ";
        }
        System.out.println(temp+this.name);
    }

    @Deprecated
    protected List<Component> getChildren() throws UnsupportedOperationException
    {
        throw new UnsupportedOperationException();
    }
}

3 Composite(树枝)

public class Composite extends Component
{
    private LinkedList<Component> children;

    public Composite(String name)
    {
        super(name);
        this.children = new LinkedList<>();
    }

    public void add(Component component)
    {
        this.children.add(component);
    }

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

    @Override
    public LinkedList<Component> getChildren()
    {
        return children;
    }

    @Override
    protected void operation(int depth)
    {
        String temp = "";
        for(int i=0;i<depth;i++)
        {
            temp += "    ";
        }

        LinkedList<Component> children = this.getChildren();
        System.out.println(temp+this.name);
        for (Component c : children) {
            c.operation(depth+1);
        }
    }
}

4 測试代码

public class MainTest
{
    public static void main(String[] args)
    {
        Composite root = new Composite("树根");

        Composite branch01 = new Composite("树枝01");
        Composite branch02 = new Composite("树枝02");
        Composite branch03 = new Composite("树枝03");
        Composite branch04 = new Composite("树枝04");

        branch01.add(new Leaf("树叶01"));
        branch01.add(new Leaf("树叶02"));
        branch03.add(new Leaf("树叶03"));
        branch03.add(new Leaf("树叶04"));
        branch03.add(new Leaf("树叶05"));
        branch01.add(branch03);

        branch02.add(new Leaf("树叶06"));
        branch02.add(new Leaf("树叶07"));
        branch02.add(new Leaf("树叶08"));
        branch04.add(new Leaf("树叶09"));
        branch04.add(new Leaf("树叶10"));
        branch02.add(branch04);

        root.add(branch01);
        root.add(branch02);

        root.operation(0);
    }
}

输出结果:

树根
    树枝01
        树叶01
        树叶02
        树枝03
            树叶03
            树叶04
            树叶05
    树枝02
        树叶06
        树叶07
        树叶08
        树枝04
            树叶09
            树叶10

上面測试代码部分构建树结构的代码着实不太好看,效率太低。

事实上。在真实应用中。

并非这样子手工地构建一棵复杂的树,应该是我们已经将整棵树的节点内容、逻辑关系都存储在数据库表中,开发者编程从数据库中的表中读取记录来构建整棵树。

透明模式 vs 安全模式

上面的代码属于透明模式,我们先看看安全模式是怎么实现的:

更改一下Component:

public abstract class Component
{
    protected String name;

    public Component(String name)
    {
        this.name = name;
    }
    protected abstract void operation(int depth);
}

再更改下Leaf

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

    @Override
    protected void operation(int depth){
        String temp = "";
        for(int i=0;i<depth;i++)
        {
            temp += "    ";
        }
        System.out.println(temp+this.name);
    }
}

被称为安全模式是由于Leaf不具有add和remove等方法,这些详细方法是被下置到Composite类中去详细实现了。

透明模式将add和remove等方法上升到抽象构建类Component中去了。那么此时Leaf类在详细实现时就必须将继承而来的add和remove等不可用、不合理的方法给凝视掉(@Deprecated),并抛出适当的异常,不提供给用户使用。至于是使用透明模式还是安全模式就仁者见仁智者见智咯。只是,在这一模式中,相对于安全性,我们比較强调透明性。

使用场景

  1. 用于对象的部分-总体层次结构,如树形菜单、目录菜单、部门组织架构等。
  2. 对用户隐藏组合对象与单个对象的不同,使得用户统一地使用组合结构中的全部对象。

优缺点

长处:使client调用简单,client能够一直的使用组合结构或当中单个对象,用户就不必关心自己处理的是单个对象还是整个组合结构,这就简化了client代码。更easy在组合体内增加对象不见。client不必由于增加了新的对象不见而更改代码。这一点符合开闭原则的要求。对系统的二次开发和功能扩展非常有利。

缺点:组合模式不easy限制组合中的构件。

Jdk中的组合模式

java.util.Map#putAll(Map)

java.util.List#addAll(Collection)

java.util.Set#addAll(Collection)

反面教材

?回忆起曾经写页面菜单的时候,从数据库中读取相似的树形结构,当时没有採用这样的组合模式,而是限定死树的最大深度(页面的菜单深度不超过3。实际上也没见到过超过3的),这样前端js代码在深度不超过3时没有问题,当超过3时,就须要又一次编写页面菜单的js代码了,这样的扩展性并不好。假设当时採用了这样的组合模式就会好非常多。

?写页面菜单已经是6年前的事了,代码早已不详~近期用项目需求要写一棵树,单例模式的。

大伙来看看有什么不妥之处。

首先定义实体类Entry

public class Entry
{
    private String name;
    //some other properties

    public Entry(String name)
    {
        super();
        this.name = name;
    }
    //getter and setter略
}

定义树节点(这里的叶子节点能够看成son==null的TreeNode。而树枝节点son!=null)

public class TreeNode
{
    private Entry entry;
    private List<TreeNode> son;
    //getter and setter略
}

定义单例树节点

public class Tree
{
    private TreeNode tree;

    private Tree()
    {
        tree = new TreeNode();
        tree.setEntry(null);
        tree.setSon(new ArrayList<TreeNode>());
    }

    public static class SingletonTreeInner
    {
        public static final Tree INSTANCE = new Tree();
    }

    public static Tree getInstance()
    {
        return SingletonTreeInner.INSTANCE;
    }

    public TreeNode getTree()
    {
        return tree;
    }
}

測试代码(根-集群-主机-虚拟机的层次关系):

    public static void insertData()
    {
        Tree root = Tree.getInstance();
        List<TreeNode> rootList = root.getTree().getSon();

        //add cluster into root node
        TreeNode cluster = new TreeNode();
        Entry entry1 = new Entry("cluster1");
        cluster.setEntry(entry1);
        cluster.setSon(null);
        rootList.add(cluster);

        //add host into cluster node
        TreeNode host = new TreeNode();
        Entry entry2 = new Entry("host1");
        host.setEntry(entry2);
        host.setSon(null);
        if(cluster.getSon() == null)
        {
            cluster.setSon(new ArrayList<TreeNode>());
        }
        List clusterList = cluster.getSon();
        clusterList.add(host);

        //add vm into host node
        TreeNode vm = new TreeNode();
        Entry entry3 = new Entry("vm1");
        vm.setEntry(entry3);
        vm.setSon(null);
        if(host.getSon() == null)
        {
            host.setSon(new ArrayList<TreeNode>());
        }
        List hostList = host.getSon();
        hostList.add(vm);
    }

大伙比对组合模式来看看这段代码有什么欠妥之处,欢迎在下方留言探讨。

參考资料

1. 《23种设计模式

2. 《细数JDK里的设计模式

3. 《组合模式(Composite)的安全模式与透明模式

时间: 2024-11-10 20:59:16

设计模式:组合模式(Composite)的相关文章

设计模式 - 组合模式(composite pattern) 详解

组合模式(composite pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy 组合模式: 允许你将对象组合成树形结构来表现"整体/部分"层次结构. 组合能让客户以一致的方法处理个别对象以及组合对象. 建立组件类(Component), 组合类(composite)和叶子类(leaf)继承组件类, 客户类(client)直接调用最顶层的组合类(composite)即可. 具体方法: 1. 组件类(component), 包含组合

设计模式 - 组合模式(composite pattern) 迭代器(iterator) 详解

组合模式(composite pattern) 迭代器(iterator) 详解 本文地址: http://blog.csdn.net/caroline_wendy 参考组合模式(composite pattern): http://blog.csdn.net/caroline_wendy/article/details/36895627 在组合模式(composite pattern)添加迭代器功能, 遍历每一个组合(composite)的项. 具体方法: 1. 抽象组件类(abstract

说说设计模式~组合模式(Composite)

返回目录 何时能用到它? 组合模式又叫部分-整体模式,在树型结构中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦.对于今天这个例子来说,它可以很清楚的说明组合模式的用意,首先是一个Graphics对象,它表示是一绘图功能(树根),而circle,line和rectangle分别是简单的图形,它们内部不能再有其它图形了(相当于树叶),而picture是一个复杂图形,它由circle,line和rectangle组成(相当于树

设计模式 -- 组合模式(Composite)

写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------主要内容包括: 初识组合模式,包括:定义.结构.参考实现 体会组合模式,包括:场景问题.不用模式的解决方案.使用模式的解决方案 理解组合模式,包括:认识组合模式.安全性和透明性.父组件引用.环状引用.组合模式的优缺点 思考组合模式,包括:组合模式的本质.何时选用 参考内容: 1.<研磨设计模式> 一书,作者:陈臣.王斌 --

设计模式组合模式(Composite)精华

23种子GOF设计模式一般分为三类:创建模式.结构模型.行为模式. 创建模式抽象的实例,他们帮助如何创建一个系统独立.这是一个这些对象和陈述的组合. 创建使用继承类的类架构更改实例.的对象类型模型的建立也将委托实例化一个对象. 创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些详细的类的信息封装起来.第二,它们隐藏了这些类的实例是怎样被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此.创建型模式在什么被创建.谁创建它,它是怎样被创建的,以及何时创建这些方

设计模式--组合模式Composite(结构型)

一.概念 组合模式允许你将对象组合成树形结构来表现"整体/部分"层次结构.组合能让客户以一致的方式处理个别对象以及对象组合. 二.UML图 1.Component(对象接口),定义了对象可以做的事情. 2.Leaf(叶子结点对象) 3.Composite(其他结点对象,包含其他结点或者叶子节点) 三.例子 快递公司一般都有层级结构 /** * 顺丰公司抽象类 * 定义了公司可以做哪些事情 * @author eason * */ public abstract class SFComp

设计模式 -- 组合模式 (Composite Pattern)

定义: 对象组合成部分整体结构,单个对象和组合对象具有一致性. 看了下大概结构就是集团总公司和子公司那种层级结构. 角色介绍: Component :抽象根节点:其实相当去总公司,抽象子类共有的方法: Composite :相当于总公司的智能部门,也分管子公司,通过集合存储子节点对象,提供增删获取子节点对象的方法: leaf:子节点,相当于集团子公司,总公司具有的智能,子公司也具有,因此子节点具有总节点拥有的所有抽象方法以及提供给子类的方法. Client:通过抽象跟节点操作子节点的对象.

设计模式之组合模式(Composite)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

设计模式(七)组合模式Composite(结构型)

设计模式(七)组合模式Composite(结构型) 1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 我们可以使用简单的对象组合成复杂的对象,而这个复杂对象有可以组合成更大的对象.我们可以把简单这些对象定义成类,然后定义一些容器类来存储这些简单对象.客户端代码必须区别对象简单对象和容器对象,而实际上大多数情况下用户认为它们是一样的.对这些类区别使用,使得程序更加复杂.递归使用的时候跟麻烦,而我们如何

设计模式之组合模式---Composite Pattern

模式的定义 组合模式(Composite Pattern)定义如下: Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly. 将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性.