zoukankan      html  css  js  c++  java
  • 设计模式:组合模式(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)的安全模式与透明模式

  • 相关阅读:
    PCB genesis方槽加内角槽孔实现方法
    PCB genesis连孔加除毛刺孔(槽孔与槽孔)实现方法(三)
    PCB genesis连孔加除毛刺孔(圆孔与槽孔)实现方法(二)
    PCB genesis连孔加除毛刺孔(圆孔与圆孔)实现方法(一)
    为什么要用Redis而不直接用Map做缓存
    Linux 查询端口被占用命令
    HashMap 和 Hashtable 的区别
    RandomAccess是什么
    接口和抽象类的区别是什么?
    为什么 Java 中只有值传递?
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/7134187.html
Copyright © 2011-2022 走看看