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

博客 动态
0 209
优雅殿下
优雅殿下 2022-03-02 22:56:02
悬赏:0 积分 收藏

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

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.txtroot 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 缺点

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

posted @ 2022-03-02 22:35 小猪爸爸 阅读(0) 评论(0) 编辑 收藏 举报
回帖
    优雅殿下

    优雅殿下 (王者 段位)

    2018 积分 (2)粉丝 (47)源码

    小小码农,大大世界

     

    温馨提示

    亦奇源码

    最新会员