• 【趣味设计模式系列】之【组合模式】


     


    1. 简介

    组合模式(Composite Pattern):将对象组合成树形结构以表示部分-整体的层次关系。

    2. 示例

    假设要设计一个文件系统的目录,需要灵活的在某个目录下添加、删除目录或文件,统计指定目录下的文件个数,计算指定目录下的文件大小。

    设计类图如下:

    抽象类Node

    package com.wzj.composite;
    
    /**
     * @Author: wzj
     * @Date: 2020/9/23 15:33
     * @Desc:
     */
    public abstract class Node {
    
        //文件路径
        protected String path;
    
        public Node(String path) {
            this.path = path;
        }
    
        public String getPath() {
            return path;
        }
    
        // 统计目录下文件数目
        public abstract int countNumOfFiles();
    
        // 统计目录下文件大小
        public abstract long countSizeOfFiles();
    
        // 打印路径
        public abstract void print();
    
    }
    

    文件类FileNode

    package com.wzj.composite;
    
    import java.io.File;
    
    /**
     * @Author: wzj
     * @Date: 2020/9/23 16:38
     * @Desc:
     */
    public class FileNode extends Node {
        public FileNode(String path) {
            super(path);
        }
    
        @Override
        public String getPath() {
            return super.getPath();
        }
    
        @Override
        public int countNumOfFiles() {
            return 1;
        }
    
        @Override
        public long countSizeOfFiles() {
            File file = new File(path);
            if (!file.exists()) return 0;
            return file.length();
        }
    
    
        @Override
        public void print() {
            System.out.println(path);
        }
    }
    
    

    目录类DirectorNode

    package com.wzj.composite;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @Author: wzj
     * @Date: 2020/9/23 16:48
     * @Desc:
     */
    public class DirectoryNode extends Node{
        public List<Node> list = new ArrayList<>();
        public DirectoryNode(String path) {
            super(path);
        }
    
        @Override
        public String getPath() {
            return super.getPath();
        }
    
        @Override
        public int countNumOfFiles() {
            int num = 0;
            for (Node node : list) {
                num += node.countNumOfFiles();
            }
            return num;
        }
    
        @Override
        public long countSizeOfFiles() {
            long size = 0;
            for (Node node : list) {
                size += node.countSizeOfFiles();
            }
            return size;
        }
    
        @Override
        public void print() {
            System.out.println(path);
        }
    
        public void addSubNode(Node node) {
            list.add(node);
        }
    
        public void removeSubNode(Node node) {
            int size = list.size();
            int i = 0;
            for (; i < size; ++i) {
                if (list.get(i).getPath().equalsIgnoreCase(node.getPath())) {
                    break;
                }
            }
    
            if (i < size) {
                list.remove(i);
            }
        }
    
    }
    
    

    客户端Client

    package com.wzj.composite;
    
    /**
     * @Author: wzj
     * @Date: 2020/9/23 20:44
     * @Desc:
     */
    public class Client {
        public static void main(String[] args) {
            DirectoryNode root = new DirectoryNode("root");
            DirectoryNode chapter1 = new DirectoryNode("chapter1");
            DirectoryNode chapter2 = new DirectoryNode("chapter2");
    
            Node r1 = new FileNode("r1.txt");
            Node c11 = new FileNode("c11.txt");
            Node c12 = new FileNode("c12.txt");
    
            DirectoryNode b21 = new DirectoryNode("section21");
    
            Node c211 = new FileNode("c211.txt");
            Node c212 = new FileNode("c212.txt");
    
            root.addSubNode(chapter1);
            root.addSubNode(chapter2);
            root.addSubNode(r1);
    
            chapter1.addSubNode(c11);
            chapter1.addSubNode(c12);
            chapter2.addSubNode(b21);
    
            b21.addSubNode(c211);
            b21.addSubNode(c212);
    
            printTree(root, 0);
    
            System.out.println("root files num:" + root.countNumOfFiles());
            System.out.println("/root/chapter1/ files num:" + chapter2.countNumOfFiles());
    
        }
    
        // 打印树状结构
        public static void printTree(Node root, int depth) {
            for (int i = 0; i < depth; i++) {
                System.out.print("--");
            }
            root.print();
            if(root instanceof DirectoryNode) {
                for (Node n : ((DirectoryNode)root).list) {
                    printTree(n, depth + 1);
                }
            }
        }
    }
    
    

    结果

    root
    --chapter1
    ----c11.txt
    ----c12.txt
    --chapter2
    ----section21
    ------c211.txt
    ------c212.txt
    --r1.txt
    root files num:5
    /root/chapter1/ files num:2
    

    3. 源码分析

    SpringMVC中对参数的解析使用的是HandlerMethodArgumentResolver接口,该类有一个实现类为HandlerMethodArgumentResolverComposite,为组合类,又持有其他HandlerMethodArgumentResolver对象,在它的实现方法中是对其他组合模式中的节点进行循环处理,从而选择最适合的一个。

    public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
    
            // 对参数解析器的引用
    	private final List<HandlerMethodArgumentResolver> argumentResolvers =
    			new LinkedList<HandlerMethodArgumentResolver>();
    
            // 对其所拥有的对象循环,找到最适合的参数解析器
            private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
    		HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
    		if (result == null) {
    			for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
    				if (logger.isTraceEnabled()) {
    					logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
    							parameter.getGenericParameterType() + "]");
    				}
    				if (methodArgumentResolver.supportsParameter(parameter)) {
    					result = methodArgumentResolver;
    					this.argumentResolverCache.put(parameter, result);
    					break;
    				}
    			}
    		}
    		return result;
    	}
    
    

    4. 总结

    4.1 优点

    • 高层调用简单
      一棵树形机构中的所有节点都是Component,局部和整体对调用者来说没有任何区别,也就是说,高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码。
    • 节点自由增加
      使用了组合模式后,我们可以看看,如果想增加一个树枝节点、树叶节点是不是都很容易,只要找到它的父节点就成,非常容易扩展,符合开闭原则,对以后的维护非常有利。

    4.2 缺点

    组合模式不容易限制组合中的构件。


    __EOF__

    本文作者小猪爸爸
    本文链接https://www.cnblogs.com/father-of-little-pig/p/13792325.html
    关于博主:不要为了技术而技术,总结分享技术,感恩点滴生活!
    版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
    声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
  • 相关阅读:
    多台云服务器的 Kubernetes 集群搭建
    利用cmd(命令提示符)安装mysql&&配置环境
    高效备考2025年AMC8数学竞赛:2000-2024年AMC8真题练一练
    ffmpeg编译 Error: operand type mismatch for `shr‘
    最佳联盟营销软件解决方案:简化你的联盟管理
    IXFP4N100参数及代换型号 数据表(PDF)中文资料
    sci论文、ei论文和ieee论文三者之间有什么区别?
    【图像处理】【应用程序设计】加载,编辑和保存图像数据、图像分割、色度键控研究(Matlab代码实现)
    分布式锁的实现原理
    Nginx服务之Rewrite
  • 原文地址:https://www.cnblogs.com/father-of-little-pig/p/13792325.html