zoukankan      html  css  js  c++  java
  • 组合模式

    组合模式

    标签 : Java与设计模式


    组合模式: 将对象组合成树形结构以表示‘部分-整体’的层次结构, 使得用户对单个对象和组合对象的使用具有一致性.

    • 解析
      • 组合模式描述了如何将容器和叶子节点进行递归组合, 使用户在使用时可一致的对待容器和叶子, 为处理树形结构提供了完美的解决方案.
      • 当容器对象的指定方法被调用时, 将遍历整个树形结构, 并执行调用. 整个过程递归处理.

        (图片来源: 设计模式: 可复用面向对象软件的基础)

    模式实现

    案例: 杀毒软件
    


    使对文件(Image/Text/Video/…)杀毒与对文件夹(Folder)的杀毒暴露统一接口.


    Component

    • 组合模式中的对象声明接口, 在适当情况下, 实现所有类共有接口的默认行为.
    • 声明一个接口用于访问和管理Component子组件.
    /**
     * @author jifang
     * @since 16/8/24 上午10:19.
     */
    public abstract class AbstractFileComponent {
    
        protected String name;
    
        protected AbstractFileComponent(String name) {
            this.name = name;
        }
    
        protected void printDepth(int depth) {
            for (int i = 0; i < depth; ++i) {
                System.out.print('-');
            }
        }
    
        protected abstract void add(AbstractFileComponent component);
    
        protected abstract void remove(AbstractFileComponent component);
    
        protected abstract void killVirus(int depth);
    }

    Leaf

    • 叶子对象: 定义没有有分支节点的行为:
    class ImageFileLeaf extends AbstractFileComponent {
    
        public ImageFileLeaf(String name) {
            super(name);
        }
    
        @Override
        public void add(AbstractFileComponent component) {
            throw new NotImplementedException(this.getClass() + " not implemented this method");
        }
    
        @Override
        public void remove(AbstractFileComponent component) {
            throw new NotImplementedException(this.getClass() + " not implemented this method");
        }
    
        @Override
        public void killVirus(int depth) {
            printDepth(depth);
            System.out.println("图片文件 [" + name + "]杀毒");
        }
    }
    
    class TextFileLeaf extends AbstractFileComponent {
    
        public TextFileLeaf(String name) {
            super(name);
        }
    
        @Override
        public void add(AbstractFileComponent component) {
            throw new NotImplementedException(this.getClass() + " not implemented this method");
        }
    
        @Override
        public void remove(AbstractFileComponent component) {
            throw new NotImplementedException(this.getClass() + " not implemented this method");
        }
    
        @Override
        public void killVirus(int depth) {
            printDepth(depth);
            System.out.println("文本文件 [" + name + "]杀毒");
        }
    }
    
    class VideoFileLeaf extends AbstractFileComponent {
    
        public VideoFileLeaf(String name) {
            super(name);
        }
    
        @Override
        public void add(AbstractFileComponent component) {
            throw new NotImplementedException(this.getClass() + " not implemented this method");
        }
    
        @Override
        public void remove(AbstractFileComponent component) {
            throw new NotImplementedException(this.getClass() + " not implemented this method");
        }
    
        @Override
        public void killVirus(int depth) {
            printDepth(depth);
            System.out.println("视频文件 [" + name + "]杀毒");
        }
    }

    Composite

    • 容器对象: 定义有分支节点的行为, 用来存储子部件, 实现与子部件有关的操作:
    public class FolderFileComposite extends AbstractFileComponent {
    
        private List<AbstractFileComponent> components = new LinkedList<>();
    
        public FolderFileComposite(String name) {
            super(name);
        }
    
        @Override
        public void add(AbstractFileComponent component) {
            components.add(component);
        }
    
        @Override
        public void remove(AbstractFileComponent component) {
            components.remove(component);
        }
    
        @Override
        public void killVirus(int depth) {
            printDepth(depth);
            System.out.println("目录 [" + name + "]杀毒");
    
            for (AbstractFileComponent component : components) {
                component.killVirus(depth + 2);
            }
        }
    }
    • Client
    public class Client {
    
        @Test
        public void client() {
            ImageFileLeaf image = new ImageFileLeaf("九寨沟.jpg");
            VideoFileLeaf video = new VideoFileLeaf("龙门飞甲.rmvb");
            TextFileLeaf text = new TextFileLeaf("解忧杂货店.txt");
    
            FolderFileComposite home = new FolderFileComposite("/home");
            home.add(image);
            home.add(video);
            home.add(text);
    
            FolderFileComposite root = new FolderFileComposite("/");
            root.add(home);
            root.add(new TextFileLeaf("/authorized_keys"));
            root.add(new FolderFileComposite("/etc"));
    
            root.killVirus(0);
    
        }
    }

    上面的实现方式是透明方式: 直接在Component中声明add()/remove(). 这样做的好处是叶节点和枝节点对于外界没有任何区别, 他们具有完全一致的行为接口. 但问题是对叶节点实现add()/remove()没有任何意义. 所以还有另一种实现方式安全方式, 也就是在Component中不去声明add()/remove(), 而是在Composite声明所有用来管理子类对象的方法, 不过由于不够透明, 所以叶节点与枝节点将不具有相同接口, 客户端调用需要作出相应判断, 带来了不便, 关于该问题的详细信息可参考: 组合模式(Composite)的安全模式与透明模式.


    小结

    • 组合模式定义了基本对象组合对象的类层次结构, 基本对象可以被组合成更复杂的组合对象, 而这个组合对象又可以被组合, 这样不断地递归下去, 这样在客户代码中任何用到基本对象的地方都可以使用组合对象.
    • 用户不用关心到底是处理一个叶节点还是处理一个枝节点, 也用不着为定义组合而写一些选择判断语句.

    总的来说: 组合模式让用户可以一致地使用组合结构单个对象.

    • 场景
      当需求中是体现部分整体层次的结构时, 以及希望用户可以忽略组合对象与单个对象的不同, 统一地使用组合中的所有对象时, 就应该考虑使用组合模式了:
      • 操作系统资源管理器
      • GUI容器视图
      • XML文件解析
      • OA系统中组织机构处理
      • Junit单元测试框架
        • TestCase(叶子)、TestUnite(容器)、Test接口(抽象)

    参考
    设计模式: 可复用面向对象软件的基础
    大话设计模式
    高淇讲设计模式
    JAVA设计模式十七–Composite(组合模式)
    设计模式系列-组合模式
    组合模式(Composite)的安全模式与透明模式

  • 相关阅读:
    博客中引用的概念
    重构博客写作
    做中学之教与学工具箱
    做中学之效率工具箱
    两个月选一本理想教材
    《敏捷革命》读书笔记
    《Java2 实用教程(第五版)》学习指导
    得到.每天听本书
    「2017年教育部-永信至诚产学合作协同育人网络空间安全专业课程教学研讨会」参会总结
    Ditto在教学上的应用
  • 原文地址:https://www.cnblogs.com/itrena/p/5926882.html
Copyright © 2011-2022 走看看