组合设计模式

目录

前言:

 组合模式的原理与实现

总结:

参考资料:


前言:

    组合模式是一种比较容易混淆的设计模式,主要在于组合二字,我们知道有个设计原则组合优于继承,这里的组合和组合设计模式又不一样?


 组合模式的原理与实现

     组合模式就是将一组对象组织成树形结构,以表示一种“部分-整体”的层次结构。组合让客户端可以统一单个对象和组合对象的处理逻辑。

这样说可能会有些抽象,接下来我们举例进行说明。

假设我们有这样一个需求:设计一个类来表示文件系统中的目录,能方便地实现下面这些功能:

动态地添加、删除某个目录下的子目录或文件;

  • 统计指定目录下的文件个数;
  • 统计指定目录下的文件总大小。
  • 
    public class FileSystemNode {
      private String path;
      private boolean isFile;
      private List<FileSystemNode> subNodes = new ArrayList<>();
    
      public FileSystemNode(String path, boolean isFile) {
        this.path = path;
        this.isFile = isFile;
      }
    
      public int countNumOfFiles() {
        // TODO:...
      }
    
      public long countSizeOfFiles() {
        // TODO:...
      }
    
      public String getPath() {
        return path;
      }
    
      public void addSubNode(FileSystemNode fileOrDir) {
        subNodes.add(fileOrDir);
      }
    
      public void removeSubNode(FileSystemNode fileOrDir) {
        int size = subNodes.size();
        int i = 0;
        for (; i < size; ++i) {
          if (subNodes.get(i).getPath().equalsIgnoreCase(fileOrDir.getPath())) {
            break;
          }
        }
        if (i < size) {
          subNodes.remove(i);
        }
      }
    }

    如果我们将文件和目录进行区分设计,定义为filedirectrory两个类。

  • 
    public abstract class FileSystemNode {
      protected String path;
    
      public FileSystemNode(String path) {
        this.path = path;
      }
    
      public abstract int countNumOfFiles();
      public abstract long countSizeOfFiles();
    
      public String getPath() {
        return path;
      }
    }
    
    public class File extends FileSystemNode {
      public File(String path) {
        super(path);
      }
    
      @Override
      public int countNumOfFiles() {
        return 1;
      }
    
      @Override
      public long countSizeOfFiles() {
        java.io.File file = new java.io.File(path);
        if (!file.exists()) return 0;
        return file.length();
      }
    }
    
    public class Directory extends FileSystemNode {
      private List<FileSystemNode> subNodes = new ArrayList<>();
    
      public Directory(String path) {
        super(path);
      }
    
      @Override
      public int countNumOfFiles() {
        int numOfFiles = 0;
        for (FileSystemNode fileOrDir : subNodes) {
          numOfFiles += fileOrDir.countNumOfFiles();
        }
        return numOfFiles;
      }
    
      @Override
      public long countSizeOfFiles() {
        long sizeofFiles = 0;
        for (FileSystemNode fileOrDir : subNodes) {
          sizeofFiles += fileOrDir.countSizeOfFiles();
        }
        return sizeofFiles;
      }
    
      public void addSubNode(FileSystemNode fileOrDir) {
        subNodes.add(fileOrDir);
      }
    
      public void removeSubNode(FileSystemNode fileOrDir) {
        int size = subNodes.size();
        int i = 0;
        for (; i < size; ++i) {
          if (subNodes.get(i).getPath().equalsIgnoreCase(fileOrDir.getPath())) {
            break;
          }
        }
        if (i < size) {
          subNodes.remove(i);
        }
      }
    }

    使用代码如下:

  • 
    public class Demo {
      public static void main(String[] args) {
        /**
         * /
         * /wz/
         * /wz/a.txt
         * /wz/b.txt
         * /wz/movies/
         * /wz/movies/c.avi
         * /xzg/
         * /xzg/docs/
         * /xzg/docs/d.txt
         */
        Directory fileSystemTree = new Directory("/");
        Directory node_wz = new Directory("/wz/");
        Directory node_xzg = new Directory("/xzg/");
        fileSystemTree.addSubNode(node_wz);
        fileSystemTree.addSubNode(node_xzg);
    
        File node_wz_a = new File("/wz/a.txt");
        File node_wz_b = new File("/wz/b.txt");
        Directory node_wz_movies = new Directory("/wz/movies/");
        node_wz.addSubNode(node_wz_a);
        node_wz.addSubNode(node_wz_b);
        node_wz.addSubNode(node_wz_movies);
    
        File node_wz_movies_c = new File("/wz/movies/c.avi");
        node_wz_movies.addSubNode(node_wz_movies_c);
    
        Directory node_xzg_docs = new Directory("/xzg/docs/");
        node_xzg.addSubNode(node_xzg_docs);
    
        File node_xzg_docs_d = new File("/xzg/docs/d.txt");
        node_xzg_docs.addSubNode(node_xzg_docs_d);
    
        System.out.println("/ files num:" + fileSystemTree.countNumOfFiles());
        System.out.println("/wz/ files num:" + node_wz.countNumOfFiles());
      }
    }

    “将一组对象(员工和部门)组织成树形结构,以表示一种‘部分 - 整体’的层次结构(部门与子部门的嵌套结构)。组合模式让客户端可以统一单个对象(员工)和组合对象(部门)的处理逻辑(递归遍历)。

  • 总结:

       组合模式的设计思路,与其说是一种设计模式,倒不如说是对业务场景的一种数据结构和算法的 抽象。其中,数据可以表示成树这种数据结构,业务需求可以通过在树上的递归遍历算法来实现。

       组合模式,将一组对象组织成树形结构,将单个对象和组合对象都看做树中的节点,以统一处理逻辑,并且它利用树形结构的特点,递归地处理每个子树,依次简化代码实现。使用组合模式的前提在于,你的业务场景必须能够表示成树形结构。所以,组合模式的应用场景也比较局限,它并不是一种很常用的设计模式。

参考资料:

53 | 组合模式:如何设计实现支持递归遍历的文件系统目录树结构?-极客时间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值