設計模式之組合模式

0x01.定義與類型

  • 定義:將對象組合成樹形結構以表示「部分-總體」的層次結構,使客戶端對單個對象和組合對象保持一致的方式處理
  • 組合模式實現的最關鍵的地方是:簡單對象和複合對象必須實現相同的接口,這就是組合模式可以將組合對象和簡單對象進行一致處理的緣由。
  • 類型:結構型
  • UML類圖

clipboard.png

  • Java實現
/**
 * 組合模式統一接口類
 */
public interface Component {
    void operation();
}

/**
 * 組合類
 */
public class Composite implements Component {

    private String name;

    private List<Component> components = new ArrayList<>();

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

    public void add(Component component) {
        components.add(component);
    }

    public void remove (Component component) {
        components.remove(component);
    }

    public Component get(int index) {
        return components.get(index);
    }

    @Override
    public void operation() {
        System.out.println(this.name);
        for (Component component : components) {
            component.operation();
        }
    }
}

/**
 * 簡單類
 */
public class Leaf implements Component {

    private String name;

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

    @Override
    public void operation() {
        System.out.println(this.name);
    }

    public String getName() {
        return name;
    }
}
  • 測試與應用類
/**
 * 應用與測試
 */
public class Test {

    public static void main(String[] args) {
        Composite composite = new Composite("樹枝1");

        Leaf leaf1 = new Leaf("樹枝1樹葉1");
        Leaf leaf2 = new Leaf("樹枝1樹葉2");
        Leaf leaf3 = new Leaf("樹枝1樹葉3");

        composite.add(leaf1);
        composite.add(leaf2);
        composite.add(leaf3);

        Composite composite1 = new Composite("樹");

        Leaf leaf4 = new Leaf("樹葉4");
        Leaf leaf5 = new Leaf("樹葉5");

        composite1.add(leaf4);
        composite1.add(leaf5);
        composite1.add(composite);

        composite1.operation();
    }
}
  • 輸入結果
樹
樹葉4
樹葉5
樹枝1
樹枝1樹葉1
樹枝1樹葉2
樹枝1樹葉3
  • 組合模式中的透明式以及安全式html

    • 透明式:組合模式中的抽象構件還聲明訪問和管理子類的接口,客戶端使用的適合不須要區分葉子節點和樹枝節點,可是葉子節點自己並不存在操做方法,通常會給出默認實現,好比拋出異常。
    • 安全式:組合模式中的抽象構件不聲明管理子類的接口,把操做移交給子類完成。這樣葉子節點不須要實現操做方法,可是客戶端使用時必須作出區分,爲使用帶來麻煩。
    • 上面的方式中使用的是安全模式。
  • 組合模式中的角色java

    • 抽象構件(Component)角色:它的主要做用是爲樹葉構件和樹枝構件聲明公共接口,並實現它們的默認行爲。在透明式的組合模式中抽象構件還聲明訪問和管理子類的接口;在安全式的組合模式中不聲明訪問和管理子類的接口,管理工做由樹枝構件完成。
    • 樹葉構件(Leaf)角色:是組合中的葉節點對象,它沒有子節點,用於實現抽象構件聲明的公共接口。
    • 樹枝構件(Composite)角色:是組合中的分支節點對象,它有子節點。它實現了抽象構件角色中聲明的接口,它的主要做用是存儲和管理子部件,一般包含 add()、remove()、get() 等方法。

0x02.適用場景

  • 但願用戶忽略組合對象與單個對象的不一樣,用戶將統一地使用組合結構中的全部對象時。
  • 當想表達對象的部分-總體的層次結構時。

0x03.優勢

  • 清楚地定義分層次的複雜對象,表示對象的所有或部分層次
  • 組合模式使得客戶端代碼能夠一致地處理對象和對象容器,無需關心處理的單個對象,仍是組合的對象容器。
  • 簡化客戶端代碼
  • 符合開閉原則

0x04.缺點

  • 限制類型時會較爲複雜。
  • 使設計變得更加抽象,客戶端須要花更多時間理清類之間的層次關係。

0x05.組合模式實現樣例

使用組合模式實現目錄和課程之間的關係。
  • 由於上面給出的basic實現安全模式的,此次的樣例使用透明模式實現。
  • Java代碼
/**
 * 通用的抽象類
 */
public abstract class CatalogComponent {

    public void add (CatalogComponent catalogComponent) {
        throw new UnsupportedOperationException("不支持添加操做");
    }

    public void remove (CatalogComponent catalogComponent) {
        throw new UnsupportedOperationException("不支持刪除操做");
    }

    public String getName () {
        throw new UnsupportedOperationException("不支持獲取名稱操做");
    }

    public Double getPrice () {
        throw new UnsupportedOperationException("不支持獲取價錢操做");
    }

    public void print () {
        throw new UnsupportedOperationException("不支持打印操做");
    }

}

/**
 * 目錄
 */
public class CourseCatalog extends CatalogComponent {

    private List<CatalogComponent> itsms = new ArrayList<>();

    private String name;

    private Integer level;

    public CourseCatalog(String name, Integer level) {
        this.name = name;
        this.level = level;
    }

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

    @Override
    public void add(CatalogComponent catalogComponent) {
        this.itsms.add(catalogComponent);
    }

    @Override
    public void remove(CatalogComponent catalogComponent) {
        this.itsms.remove(catalogComponent);
    }

    @Override
    public void print() {
        System.out.println("> " + this.name);
        for (CatalogComponent catalogComponent : itsms) {
            if (this.level != null) {
                for (int i = 0; i < this.level; i ++) {
                    System.out.print("--");
                }
            }
            catalogComponent.print();
        }
    }
}

/**
 * 具體的課程
 */
public class Course extends CatalogComponent {

    private String name;

    private Double price;

    public Course(String name, Double price) {
        this.name = name;
        this.price = price;
    }

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

    @Override
    public Double getPrice() {
        return this.price;
    }

    @Override
    public void print() {
        System.out.println("> Course Name:" + this.name + ": price: " + this.price);
    }
}
  • 測試與應用
/**
 * 測試與應用
 */
public class Test {

    public static void main(String[] args) {
        CatalogComponent linuxCourse = new Course("Linux課程", 11D);
        CatalogComponent windowCourse = new Course("Window課程", 12D);

        CatalogComponent javaCourseCatalog = new CourseCatalog("Java課程目錄", 2);

        CatalogComponent mmallCourse1 = new Course("Java電商一期", 55D);
        CatalogComponent mmallCourse2 = new Course("Java電商二期", 66D);
        CatalogComponent designPattern = new Course("Java設計模式", 77D);

        javaCourseCatalog.add(mmallCourse1);
        javaCourseCatalog.add(mmallCourse2);
        javaCourseCatalog.add(designPattern);

        CatalogComponent mainCourseCatalog = new CourseCatalog("課程主目錄", 1);

        mainCourseCatalog.add(linuxCourse);
        mainCourseCatalog.add(windowCourse);
        mainCourseCatalog.add(javaCourseCatalog);

        mainCourseCatalog.print();
    }
}
  • UML類圖

clipboard.png

0x06.相關設計模式

  • 組合模式和訪問者模式linux

    • 能夠適用訪問者模式來訪問組合模式中的遞歸結構

0x07.源碼中的組合模式

  • java.awt.Container
  • HashMap.putAll
  • ArrayList.addAll
  • MyBatis.SqlNode

0x08.代碼地址

0x09.參考

相關文章
相關標籤/搜索