Java設(shè)計(jì)模式百例 - 合成模式

本文源碼見:https://github.com/get-set/get-designpatterns/tree/master/composite

組合模式(Composite Pattern),又叫部分整體模式,依據(jù)樹形結(jié)構(gòu)來(lái)組合對(duì)象,是用來(lái)表示部分以及整體層次的一種遞歸式結(jié)構(gòu)的模式。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它創(chuàng)建了對(duì)象組的樹形結(jié)構(gòu)。

其實(shí)現(xiàn)實(shí)世界中,這種樹狀結(jié)構(gòu)的組合還是挺普遍的:

  1. 組織結(jié)構(gòu),從CEO到基層組長(zhǎng),都有下屬,他們都相當(dāng)于“枝干”,對(duì)于基層員工就是“葉子”節(jié)點(diǎn),不過(guò)說(shuō)到底他們都是公司員工;
  2. 目錄結(jié)構(gòu),這個(gè)更好理解了,目錄里包含子目錄和文件,各層目錄相當(dāng)于樹狀結(jié)構(gòu)的“枝干”,文件相當(dāng)于“葉子”節(jié)點(diǎn),說(shuō)到底目錄和文件都是文件系統(tǒng)的組件(在Linux里,都可以看作“文件”這個(gè)大的概念,甚至鼠標(biāo)鍵盤等設(shè)備);
  3. 一句文字,無(wú)論是書信還是微博,都是由字、詞構(gòu)成的,詞呢又是由字構(gòu)成的,字和詞都可以看作句子的組成元素,二者又有包含關(guān)系。

看到這里是不是覺得已經(jīng)不用再看具體例子的代碼了呢,聰明的你估計(jì)腦海中已經(jīng)構(gòu)思除了一個(gè)小的demo了。

例子

就以文件系統(tǒng)目錄結(jié)構(gòu)為例吧。剛才說(shuō)到,無(wú)論是目錄還是文件,在Linux中我們都認(rèn)為是廣義的“文件”,為了方便闡述,我們把這個(gè)廣義的“文件”叫做Entry吧,顯然目錄DirectoryFile都是一種Entry。如下:

Entry.java

public abstract class Entry {
    public abstract String getName();
    public abstract int getSize();
    public abstract Entry add(Entry entry) {
        throw new RuntimeException();
    }
    public void printList() {
        printList("");
    }
    public abstract void printList(String prefix);

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

File.java

public class File extends Entry {
    private String name;
    private int size;

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

    public String getName() {
        return this.name;
    }

    public int getSize() {
        return this.size;
    }

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

Directory.java

public class Directory extends Entry {
    private String name;
    private List<Entry> items = new ArrayList<Entry>();

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

    public String getName() {
        return this.name;
    }

    public int getSize() {
        int size = 0;
        Iterator it = this.items.iterator();
        while (it.hasNext()) {
            Entry entry = (Entry) it.next();
            size += entry.getSize();
        }
        return size;
    }

    public Entry add(Entry entry) {
        items.add(entry);
        return this;
    }

    public void printList(String prefix) {
        System.out.println(prefix + "/" + getName());
        Iterator it = items.iterator();
        while (it.hasNext()) {
            Entry entry = (Entry) it.next();
            entry.printList(prefix + "/" + this.name);
        }
    }
}

測(cè)試一下:

Client.java

public class Client {
    public static void main(String[] args) {
        Entry bindir = new Directory("bin");
        Entry usrdir = new Directory("usr");
        Entry tmpdir = new Directory("lib");

        bindir
                .add(new File("bash", 4))
                .add(new File("ls", 6))
                .add(new File("ip", 8));

        usrdir
                .add(new Directory("bin")
                    .add(new File("top", 10))
                    .add(new File("ssh", 12)))
                .add(new Directory("local")
                    .add(new Directory("bin")
                        .add(new File("eclipse", 4))
                        .add(new File("idea", 4)))
                    .add(new Directory("src")));

        tmpdir
                .add(new File("test.txt", 12));

        Entry rootdir = new Directory("root");
        rootdir.add(bindir).add(usrdir).add(tmpdir);
        rootdir.printList();
    }
}

輸出結(jié)果:

/root
/root/bin
/root/bin/bash(4)
/root/bin/ls(6)
/root/bin/ip(8)
/root/usr
/root/usr/bin
/root/usr/bin/top(10)
/root/usr/bin/ssh(12)
/root/usr/local
/root/usr/local/bin
/root/usr/local/bin/eclipse(4)
/root/usr/local/bin/idea(4)
/root/usr/local/src
/root/lib
/root/lib/test.txt(12)

總結(jié)

合成設(shè)計(jì)模式是一種辨識(shí)度比較高,應(yīng)用場(chǎng)景相對(duì)比較明確的設(shè)計(jì)模式,因此相對(duì)來(lái)說(shuō)也比較好理解。主要特征就兩條:

  1. 無(wú)論是“枝干“還是”葉子“,都是樹的“組成部分”,因此都有共同的抽象,而“枝干”中的list成員變量引用的也是這個(gè)共同抽象的列表。概括地說(shuō)就是“整體”和“部分”具有一致性,是一種遞歸包含關(guān)系;
  2. 通常有一個(gè)“添加方法”,類似于本例的add(),因?yàn)槭沁f歸操作,一視同仁,這個(gè)方法通常定義在抽象類中,默認(rèn)拋出異常,以便適用“葉子”節(jié)點(diǎn)無(wú)法添加子節(jié)點(diǎn)的情況。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容