1. 程式人生 > >Composite模式(組合設計模式)

Composite模式(組合設計模式)

Composite 設計模式?

在計算機的檔案系統中,有“資料夾”的概念(在有些作業系統(Linux作業系統)中,也稱為“目錄”)。資料夾裡面既可以放入檔案,也可以放入其他資料夾(子資料夾)。在子資料夾中,一樣地既可以放入檔案,也可以放入子資料夾。可以說,資料夾是形成了一種容器結構、遞迴結構。

  • 結構模式:能夠使容器與內容具有一致性,創造出遞迴結構的模式就是Composite模式。

  • 關注點:使用Composite模式可以使容器與內容具有一致性,也可以稱其為多個和單個的一致性,即將多個物件結合在一起,當作一個物件進行處理。

理清職責

  • 到處存在的遞迴結構:
  1. 在視窗系統中,一個視窗可以含有一個子視窗, 2.在文章的列表中,各列表之間可以相互巢狀,這也是一種遞迴結構。 3.將多條計算機命令合併為一條巨集命令時,如果使用遞迴結構實現巨集命。 4.樹結構的資料結構都適用Composite模式。
  • 實現:演示資料夾 檔案子項之間的層次關係 名字===================>>>說明 Entry || 抽象類,用來實現File類和Directory類的一致性 File || 表示檔案的類 Directory || 表示資料夾的類 FileTreatementException || 表示向檔案中增加Entry時發生的異常的類 Main || 測試程式行為的類

  • Add()方法的存在位置:
  1. 存在Entry 丟擲異常。
  2. 存在Entry 中什麼也不做。
  3. 宣告在Entry中為抽象方法 不去實現。
  4. 直接定義在Directory類中,但是需要關注型別之間的轉換。

UML

類圖:

Code

  • Entry

···

public abstract class Entry {

/**
 * 1. 檔名
 * 2. 檔案大小
 * @return
 */
public abstract String getName();
public abstract int getSize();

/**
 * Directory  增加條目
 * File 不能增加條目
 */
public Entry add(Entry entry)throws FileTreatementException{
    throw new FileTreatementException();
}

public void printList(){
    printList("");
}

protected abstract void printList(String prefix);

@Override
public String toString() {
    return getName()+"("+getSize()+")";
}

}

···

  • File
public class File extends Entry {

    private String name;

    private int size;

    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    protected void printList(String prefix) {
        System.out.println(prefix+"/"+this);
    }
}

  • Directory

public class Directory extends Entry {

    private String name;

    private List<Entry> directory=new ArrayList<>();

    public Directory(String name) {
        this.name = name;
    }

    @Override
    public Entry add(Entry entry) throws FileTreatementException {
        directory.add(entry);
        return this;
    }

    @Override
    public String getName() {
        return name;
    }

    /**
     * getSize() | printList(String prefix)
     *
     * 都會遞迴去遍歷下面可能存在的 目錄或者檔案的子項
     */

    @Override
    public int getSize() {
        int size=0;
        Iterator<Entry> it = directory.iterator();
        while (it.hasNext()){
            // 這裡的Entry 可能是目錄 也可能是檔案
            Entry next = it.next();
            size+=next.getSize();
        }

        return size;
    }

    @Override
    protected void printList(String prefix) {
        // 這裡的 prefix是一個引用 this將會呼叫tostring()方法 又會繼續呼叫getName() getSize()方法
        System.out.println(prefix+"/"+this);
        Iterator<Entry> it = directory.iterator();
        while(it.hasNext()){
            // 這裡的Entry 可能是目錄 也可能是檔案
            Entry next = it.next();
            next.printList(prefix+"/"+this);
        }
    }
}


  • FileTreatementException

public class FileTreatementException extends Exception {

    public FileTreatementException() {
    }

    public FileTreatementException(String message) {
        super(message);
    }
}

  • 定義的目的結構:
start +++++++++++
/root(16000)
/root(16000)/bin(16000)
/root(16000)/bin(16000)/vi(1000)
/root(16000)/bin(16000)/notepaid(15000)
/root(16000)/temp(0)
/root(16000)/user(0)
  • MainT
public class MainT {

    public static void main(String[] args) throws FileTreatementException{

        System.out.println("start +++++++++++");

        Directory rootdir=new Directory("root");

        Directory bindir = new Directory("bin");
        Directory tempdir = new Directory("temp");
        Directory userdir = new Directory("user");

        rootdir.add(bindir);
        rootdir.add(tempdir);
        rootdir.add(userdir);

        bindir.add(new File("vi",1000));
        bindir.add(new File("notepaid",15000));

        rootdir.printList();
    }
}