• 设计模式(十一)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)
    

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

  • 相关阅读:
    Libvirt错误总结
    linux学习
    HMC 命令行登陆设置
    AIX扩VG和扩文件系统
    Bootstrap CSS2
    Bootstrap CSS
    JQuery的实例集合
    JQuery的noConflict()方法
    android的intent实现页面的跳转
    android的activity
  • 原文地址:https://www.cnblogs.com/BigJunOba/p/8708329.html
Copyright © 2020-2023  润新知