组合模式 - 哥,我被我妈骂了

作者: 司鑫 | 来源:发表于2017-01-01 20:53 被阅读186次

    1 介绍


    小白:大哥。我被我老妈骂了。/(ㄒoㄒ)/~~
    Acey:为什么呀?
    小白:因为我昨天用完《多色按压笔》后到处乱扔。 ,,ԾㅂԾ,,
    Acey:活该。 ε=( o`ω′)ノ
    小白:.......,不过骂完我之后,她还给我买了个笔盒。 O(∩_∩)O

    多层笔盒

    Acey:咳咳,好骚气的笔盒,还是多层的。你妈真会选。不过看到这个笔盒我又想起了组合模式,想不想知道是怎么回事呀?
    小白:,好像没的选吧。您老说吧。不过得讲的我听的懂才行哦。
    Acey:No problem!

    组合模式:又叫部分整体模式,是构造型模式的一种,是用于将一组类似的对象当做一个单个对象,然后根据树形结构组合对象。

    Acey:先来简单的解释一下吧。看你都要睡着了。。
    小白: 好哇。
    Acey多种颜色的笔笔盒的每一层就相当于一组类似的对象,而根据树状结构组合对象就是将每一层当作树枝当作树叶来组合起来,从而形成一棵树状结构。

    组合模式的几个角色:

    • Component(枝干):提供管理子节点对象的接口方法。
    • Composite(树枝):Component的实现类。
    • Leaf(叶子):Component的实现类。

    小白:额,


    能来个实例就好了?
    Acey:好吧,下面我们就来写个小demo吧。

    2 实现


    一步,先把笔盒接口创建出来

    PenBox.class

    public interface PenBox {
        //添加一层或往当前层添加笔
        public void add(PenBox penbox);
        //移除当前层或移除当前层中存放的笔
        public void remove(PenBox penbox);
        //查看当前层或当前层中的笔
        public void display();
        //获取笔盒中的所有层或当前层中的所有笔
        public List<PenBox> getChildren();
    }
    

    二步,创建一个笔盒层对象

    Layer.class

    public class Layer implements PenBox{
    
        private List<PenBox> layers;
        private String name;
    
        //给当前层一个名字
        public Layer(String name) {
            layers = new ArrayList<>();
            this.name = name;
        }
        //给当前层添加一支笔
        @Override
        public void add(PenBox penbox) {
            layers.add(penbox);
        }
        //移除当前层中的一支笔
        @Override
        public void remove(PenBox penbox) {
            layers.remove(penbox);
        }
        //显示当前层的名称
        @Override
        public void display() {
            System.out.println(name);
        }
        //获取当前层中的所有笔
        @Override
        public List<PenBox> getChildren() {
            return this.layers;
        }
    
    }
    

    三步,创建笔对象

    Pen.class

    public class Pen implements PenBox{
    
        private String name;
        
        public Pen(String name) {
            this.name = name;
        }
        
        @Override
        public void add(PenBox penbox) {
        }
    
        @Override
        public void remove(PenBox penbox) {
        }
        //显示当前笔
        @Override
        public void display() {
            System.out.println(name);
        }
    
        @Override
        public List<PenBox> getChildren() {
            return null;
        }
    
    }
    

    测试:MainClass.class

    public class MainClass {
        public static void main(String[] args) {
            //创建一个笔盒,笔盒是一个特殊的层
            PenBox penBox = new Layer("笔盒");
            //为笔盒添加两层
            PenBox penLayer = new Layer("第一层,装中性笔");
            PenBox pencilLayer = new Layer("第二层,装铅笔");
            //将第一层和第一层添加到笔盒中
            penBox.add(penLayer);
            penBox.add(pencilLayer);
            
            
            //向铅笔层中添加三支笔
            pencilLayer.add(new Pen("红色"));
            pencilLayer.add(new Pen("白色"));
            pencilLayer.add(new Pen("蓝色"));
            
            //向中性笔层中添加三支笔
            penLayer.add(new Pen("红色"));
            penLayer.add(new Pen("白色"));
            penLayer.add(new Pen("蓝色"));
            
            //显示笔盒中全部的笔
            display(penBox, 0);
        }
        //迭代打印整个笔盒
        public static void display(PenBox penbox,Integer deep){
            for(int i = 0; i < deep; ++i){
                System.out.print("-");
            }
            penbox.display();
            if(penbox instanceof Pen){
                return;
            }
            List<PenBox> children = penbox.getChildren();
            for(PenBox child : children){
                if(child instanceof Pen){
                    for(int i = 0; i <= deep; ++i){
                        System.out.print("-");
                    }
                    child.display();
                }else{
                    display(child, deep+1);
                }
            }
        }
    }
    
    运行结果

    Acey:看,我们可以用递归将整个笔盒的结构输出出来,可以看到我们将笔盒分成了两层。当然如果你还想加层的话也可以哦。
    小白:soga,那可以在某一层中再加一层嘛。🤤
    Acey:可以啊,如果你想放什么小秘密的话,也可以再在某一层中添加一层。就像大树的枝叶一样可以无限延伸

    3 特点


    高层调用底层模块简单,而且子节点可以自由增加。适合用于部分、整体设计,如菜单,文件、文件夹等。

    Acey:小白,你没睡着吧。
    小白:肯定没有哇。待我在下去消化一下。哈哈

    喜欢的话戳一下喜欢呗。
    有什么建议的话希望大家能在下方回复('')
    上一篇:外观模式 - 多色按压笔你使过没?
    下一篇:桥接模式 - 大/小白祝大家元旦Glücklich

    相关文章

      网友评论

      • 张羽辰:写的很不错,Leaf, Composite, Component 都有不错的实现,可以优化下 display 这个功能,将它放到每个 component 内部去实现,code 将会更加表意与整洁。
        司鑫:@张羽辰 嗯嗯,谢谢大牛指导 :smile:
        张羽辰:@Acey sorry 可能没表达清楚,我的意思是我们已经在接口中定义了 display 了,就表示我们需要实现它的功能,对于一个 leaf,可能只是需要打印出它的内容,对于一个 Composite,我们可以打印出他自己,也可以同时调用其子的 display,这样在 Main 函数中就不需要写那个复杂的逻辑了。

        但是,你这个逻辑有深度作为参数,也是很不错,可否试着把 deep 作为参数加入到 display 的 signature 呢? :smirk:
        司鑫:@张羽辰 每个Component?不是应该只有一个Component嘛

      本文标题:组合模式 - 哥,我被我妈骂了

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