美文网首页
设计模式学习笔记05-Composite模式

设计模式学习笔记05-Composite模式

作者: 百恼神烦 | 来源:发表于2018-06-24 12:51 被阅读0次

    本文主要是看了《设计模式》做的笔记和思考,在此分享仅代表个人观点,如有不对的地方欢迎批评和指正。

    1. 基础

    Composite(组合)模式主要是解决嵌套结构中对象之间的关系,比如文件和文件夹,这两者在大多数情况下还具有很多共同点。Composite模式的UML图如下(照着我书上画的)。


    Composite的UML图

    稍微解释一下:

    • Component 提供一个统一Leaf和Composite的抽象,里面有通用的接口。
    • Leaf 叶子节点,相当于文件系统中的文件,没有子节点。
    • Composite 类似容器的概念,相当于文件系统中的文件夹,可能有子节点。
    • Client 调用者

    这里重点是Component的统一抽象,正是因为这个才能统一Leaf和Composite的接口,因此Component中要尽可能地定义通用接口,以满足Leaf和Composite的需要。

    1.1 好处

    1. 这个模式定义了基本对象和组合对象,组合对象也可以跟其他组合对象组合成更复杂的对象;
    2. 能够方便地设计基本对象和组合对象的共同属性和行为;
    3. Leaf和Composite的子类可以方便地接入原有的体系;
    4. 可以通过递归方便地遍历整个结构

    1.2 部分实现

    在Component中,方法都应该设置为省缺实现,便于照顾叶子节点,比如其中的add操作。这样Leaf就可以不再重写add方法,缩减代码量。

    class Component{
        void add(Component cpn){
            return;
        }
    }
    

    为了保存子节点,Composite需要用到一些存储结构,比如列表、树等等,主要是看性能。

    class Composite extends Component{
        private ArrayList<Component> list;
        @Override
        void add(Component cpn){
            list.add(cpn);
        }
        // remove类似
    
        @Override
        Component getChild(int pos){
            return list.get(pos);
        }
    }
    

    2. 其他可选设计

    2.1 显式的父节点引用

    为了方便查找和遍历,可以显式地引入父节点的引用,比如这样:

    class Component{
        private Component father;
    
        protected void setFather(Component father){
            this.father = father;
        }
        public Component getFather(){
            if(father == null){
                throw new Exception("没有父节点");
            }
        }
    }
    
    class Composite extends Component{
        private ArrayList<Component> list;
        @Override
        void add(Component cpn){
            cpn.setFather(this);
            list.add(cpn);
        }
    }
    

    2.2 子节点排序

    只有排序后才能更快地进行查询,你可以根据自己使用的语言编写相应代码,比如在Java中实现Comparable接口即可在加入List时自动排序。

    2.3 缓存子节点

    为了应对频繁的检索,有时可以设置一个缓存,避免了多次遍历,提高效率,比如当你存储子节点的结构是树或者链表。

    class Composite extends Component{
        private HashMap<Integer,Component> map;
    
        private static int idHolder;
        private static Component cpnHolder;
    
        @Override
        Component getChild(int id){
            if(id != idHolder && cpnHolder == null){
                idHolder = id;
                cpnHolder = map.get(id);
            }
            return cpnHolder;
        }
    }
    

    不过需要注意的是,当子节点发生变化时也需要更新缓存,保证其正确性。

    3. 总结

    该模式很好地处理了嵌套结构中,组合对象身份多样的情况,并且提供了统一的抽象来简化代码和使用,实际的例子有Android中View与ViewGroup,有相关编程经验的读者应该深有体会。

    相关文章

      网友评论

          本文标题:设计模式学习笔记05-Composite模式

          本文链接:https://www.haomeiwen.com/subject/bmwjyftx.html