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

虚幻大学 xuhss 438℃ 0评论

Python微信订餐小程序课程视频

https://edu.csdn.net/course/detail/36074

Python实战量化交易理财系统

https://edu.csdn.net/course/detail/35475目录


回到顶部## 1. 简介

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

回到顶部## 2. 示例

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

设计类图如下:
7af5335fbd84b2cd0865a2f12a1fdcd5 - 【趣味设计模式系列】之【组合模式】

抽象类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 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 argumentResolvers =
 new LinkedList();

 // 对其所拥有的对象循环,找到最适合的参数解析器
 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__

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UUDdzz8a-1646241145244)(https://blog.csdn.net/father-of-little-pig/p/13792325.html)]小猪爸爸 本文链接:https://blog.csdn.net/father-of-little-pig/p/13792325.html关于博主:不要为了技术而技术,总结分享技术,感恩点滴生活!版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!

转载请注明:xuhss » 【趣味设计模式系列】之【组合模式】

喜欢 (0)

您必须 登录 才能发表评论!