• 设计模式(十一)Composite模式


      Composite模式模式能够使容器与内容具有一致性,创造出递归结构。有时,与将文件夹和文件都作为目录条目看待一样,将容器和内容作为同一种东西看待,可以帮助我们方便地处理问题。在容器中既可以放入内容,也可以放入小容器,然后在那个小容器中,又可以放入更小的容器。这样,就形成了容器结构、递归结构。

      示例程序类图如上图。

     1 package bigjunoba.bjtu.composite;
     2 
     3 public abstract class Entry {
     4     public abstract String getName();                               // 获取名字
     5     public abstract int getSize();                                  // 获取大小
     6     public Entry add(Entry entry) throws FileTreatmentException {   // 加入目录条目
     7         throw new FileTreatmentException();
     8     }
     9     public void printList() {                                       // 为一览加上前缀并显示目录条目一览
    10         printList("");
    11     }
    12     protected abstract void printList(String prefix);               // 为一览加上前缀
    13     public String toString() {                                      // 显示代表类的文字
    14         return getName() + " (" + getSize() + ")";
    15     }
    16 }

      Entry类是一个表示目录条目的抽象类。为了能将文件夹Directory和文件File统一起来,所以设计了Entry类。其中printList方法有两种形式,称为重载。其中带参数的printList方法可见性是protected,即只能被Entry类的子类调用。

     1 package bigjunoba.bjtu.composite;
     2 
     3 public class File extends Entry {
     4     private String name;
     5     private int size;
     6     public File(String name, int size) {
     7         this.name = name;
     8         this.size = size;
     9     }
    10     public String getName() {
    11         return name;
    12     }
    13     public int getSize() {
    14         return size;
    15     }
    16     protected void printList(String prefix) {
    17         System.out.println(prefix + "/" + this);
    18     }
    19 }

      File类是表示文件的类,调用构造函数,就会根据传入的文件名和文件大小生成文件实例。其中的this表示父类中的toString方法。

     1 package bigjunoba.bjtu.composite;
     2 
     3 import java.util.Iterator;
     4 import java.util.ArrayList;
     5 
     6 public class Directory extends Entry {
     7     private String name;                    // 文件夹的名字
     8     private ArrayList<Entry> directory = new ArrayList<Entry>();      // 文件夹中目录条目的集合
     9     public Directory(String name) {         // 构造函数
    10         this.name = name;
    11     }
    12     public String getName() {               // 获取名字
    13         return name;
    14     }
    15     
    16     public int getSize() {                  // 获取大小
    17         int size = 0;
    18         Iterator<Entry> it = directory.iterator();
    19         while (it.hasNext()) {
    20             Entry entry = (Entry)it.next();
    21             size += entry.getSize();
    22         }
    23         return size;
    24     }
    25     
    26     public Entry add(Entry entry) {         // 增加目录条目
    27         directory.add(entry);
    28         return this;
    29     }
    30     
    31     protected void printList(String prefix) {       // 显示目录条目一览
    32         System.out.println(prefix + "/" + this);
    33         Iterator<Entry> it = directory.iterator();
    34         while (it.hasNext()) {
    35             Entry entry = (Entry)it.next();
    36             entry.printList(prefix + "/" + name);
    37         }
    38     }
    39 }

      Directory类是表示文件夹的类。这里用泛型集合来保存文件夹中的目录条目。getSize方法返回集合中所有元素的大小的总和。

      这里注意size += entry.getSize();不管entry是哪个类的实例,都可以通过getSize方法得到它的大小。这就是该模式的特征--容器与内容一致性-的表现。

      注意这里使用了递归,如果entry是Directory类的实例,调用 entry.getSize()时会将该文件夹下的所有目录条目的大小加起来,如果还有子文件夹,又会调用子文件夹的getSize方法。即getSize方法的递归调用与Composite模式的结构是相对应的。

      add方法不会判断接收到的是文件夹还是文件,而是通过委托给ArrayList类来实现。printList方法也会递归调用,不多解释了。

    1 package bigjunoba.bjtu.composite;
    2 
    3 public class FileTreatmentException extends RuntimeException {
    4     public FileTreatmentException() {
    5     }
    6     public FileTreatmentException(String msg) {
    7         super(msg);
    8     }
    9 }

      由于调用add方法抛出的异常类并非Java类库的自带异常类,所以要编写自己的异常类。

     1 package bigjunoba.bjtu.composite;
     2 
     3 public class Main {
     4     public static void main(String[] args) {
     5         try {
     6             System.out.println("Making root entries...");
     7             Directory rootdir = new Directory("root");
     8             Directory bindir = new Directory("bin");
     9             Directory tmpdir = new Directory("tmp");
    10             Directory usrdir = new Directory("usr");
    11             rootdir.add(bindir);
    12             rootdir.add(tmpdir);
    13             rootdir.add(usrdir);
    14             bindir.add(new File("vi", 10000));
    15             bindir.add(new File("latex", 20000));
    16             rootdir.printList();
    17 
    18             System.out.println("");
    19             System.out.println("Making user entries...");
    20             Directory yuki = new Directory("yuki");
    21             Directory hanako = new Directory("hanako");
    22             Directory tomura = new Directory("tomura");
    23             usrdir.add(yuki);
    24             usrdir.add(hanako);
    25             usrdir.add(tomura);
    26             yuki.add(new File("diary.html", 100));
    27             yuki.add(new File("Composite.java", 200));
    28             hanako.add(new File("memo.tex", 300));
    29             tomura.add(new File("game.doc", 400));
    30             tomura.add(new File("junk.mail", 500));
    31             rootdir.printList();
    32         } catch (FileTreatmentException e) {
    33             e.printStackTrace();
    34         }
    35     }
    36 }

      Main类作为测试类,也不做过多解释。

    Making root entries...
    /root (30000)
    /root/bin (30000)
    /root/bin/vi (10000)
    /root/bin/latex (20000)
    /root/tmp (0)
    /root/usr (0)
    
    Making user entries...
    /root (31500)
    /root/bin (30000)
    /root/bin/vi (10000)
    /root/bin/latex (20000)
    /root/tmp (0)
    /root/usr (1500)
    /root/usr/yuki (300)
    /root/usr/yuki/diary.html (100)
    /root/usr/yuki/Composite.java (200)
    /root/usr/hanako (300)
    /root/usr/hanako/memo.tex (300)
    /root/usr/tomura (900)
    /root/usr/tomura/game.doc (400)
    /root/usr/tomura/junk.mail (500)
    

       测试结果如上图,一目了然。

  • 相关阅读:
    centos 安装 TortoiseSVN svn 客户端
    linux 定时任务 日志记录
    centos6.5 安装PHP7.0支持nginx
    linux root 用户 定时任务添加
    composer 一些使用说明
    laravel cookie写入
    laravel composer 安装指定版本以及基本的配置
    mysql 删除重复记录语句
    linux php redis 扩展安装
    linux php 安装 memcache 扩展
  • 原文地址:https://www.cnblogs.com/BigJunOba/p/8708329.html
Copyright © 2020-2023  润新知