設計模式 - 組合模式詳解

基本介紹

一、組合模式(Composite Pattern)又叫部分總體模式,他建立了對象組的樹形結構,將對象組合成樹狀結構以表示「總體 - 部分」的層次關係。java

二、組合模式使得用戶對單個對象和組合對象的訪問具備一致性,即:組合能讓客戶以一致的方式處理個別對象以及組合對象git

模式結構

Component(抽象構件):定義參加組合對象的公有方法和屬性,能夠定義一些默認的行爲和屬性。github

Composite(容器構件):樹枝對象,它的做用是組合樹枝結點和葉子結點造成一個樹形結構。安全

Leaf(葉子構件):葉子構件的下面沒有其餘分支,也就是遍歷的最小單位。ide


組合模式有兩種實現:安全模式和透明模式,其結構以下圖所示測試

  • 安全組合模式:在抽象構件角色中沒有聲明任何用於管理成員對象的方法,而是在容器構件 Composite 類中聲明並實現這些方法。
  • 透明組合模式:抽象構建角色中聲明瞭全部用於管理成員對象的方法,對其它構件公開透明。

簡單案例

要求:在頁面展現出公司的部門組成(一個公司有多個部門,每一個部門有多個小組);this

這是一種很明顯的樹形結構,所以能夠用組合模式解決code

「抽象構件」:OrganizationComponentcomponent

public abstract class OrganizationComponent {
    private String name;

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

    protected void add(OrganizationComponent component) {
        throw new UnsupportedOperationException("不支持添加操做");
    }

    protected void remove(OrganizationComponent component) {
        throw new UnsupportedOperationException("不支持刪除操做");
    }

    protected abstract void print();


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

「容器構件」:Company、Department對象

public class Company extends OrganizationComponent {
    private List<OrganizationComponent> components = new ArrayList<>();

    public Company(String name) {
        super(name);
    }

    @Override
    protected void add(OrganizationComponent component) {
        components.add(component);
    }

    @Override
    protected void remove(OrganizationComponent component) {
        components.remove(component);
    }

    @Override
    protected void print() {
        System.out.println("======="+getName()+"=======");
        for (OrganizationComponent component : components) {
            component.print();
        }
    }

    @Override
    public String getName() {
        return super.getName();
    }
}
public class Department extends OrganizationComponent {
    private List<OrganizationComponent> components = new ArrayList<>();

    public Department(String name) {
        super(name);
    }

    @Override
    protected void add(OrganizationComponent component) {
        components.add(component);
    }

    @Override
    protected void remove(OrganizationComponent component) {
        components.remove(component);
    }

    @Override
    protected void print() {
        System.out.println("======="+getName()+"=======");
        for (OrganizationComponent component : components) {
            component.print();
        }
    }

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

「葉子構件」:Group,葉子構件不沒有子節點了,因此不須要添加、刪除之類的方法

public class Group extends OrganizationComponent {
    public Group(String name) {
        super(name);
    }

    @Override
    protected void print() {
        System.out.println(getName());
    }

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

「測試類」:Client

public class Client {
    @Test
    public void test01(){
        OrganizationComponent company = new Company("阿里巴巴");

        OrganizationComponent department1 = new Department("市場部");
        OrganizationComponent department2 = new Department("技術部");

        OrganizationComponent group1 = new Group("市場一組");
        OrganizationComponent group2 = new Group("市場二組");
        OrganizationComponent group3 = new Group("技術一組");
        OrganizationComponent group4 = new Group("技術二組");

        //添加部門
        company.add(department1);
        company.add(department2);
        //添加小組
        department1.add(group1);
        department1.add(group2);
        department2.add(group3);
        department2.add(group4);

        //打印結果
        company.print();
    }
}

「運行結果」

=======阿里巴巴=======
=======市場部=======
市場一組
市場二組
=======技術部=======
技術一組
技術二組

在 HashMap 中的應用

在 Java(jdk 1.8爲例) 的集合類 HashMap 中,抽象構件是 Map,容器構件是 HashMap,葉子構件是 Node

進入源碼能夠看見,在 Map 中定義了許多公共方法

HashMap 實現了 Map,並對一些方法重寫,並且 HashMap 中有一個靜態內部類 Node,它就充當了葉子構件的角色,Node 中去除了 put、putAll 等方法,下面也沒有子結點了

使用:

@Test
public void test02(){
    Map<String, String> map = new HashMap<>();
    map.put("k1", "v1");
    map.put("k2", "v2");
    System.out.println(map);
}

當咱們 put 一個鍵值對的時候,在 HashMap 內部會調用 putVal 方法,將鍵值對封裝爲 Node。

總結

一、簡化客戶端操做。客戶端只須要面對一致的對象而不用考慮總體部分或者節點葉子的問題。

二、具備較強的擴展性。當咱們要更改組合對象時,咱們只須要調整內部的層次關係,客戶端不用作出任何改動。

三、方便建立出複雜的層次結構。客戶端不用理會組合裏面的組成細節,容易添加節點或者葉子從而建立出複雜的樹形結構。

四、須要遍歷組織機構,或者處理的對象具備樹形結構時,很是適合使用組合模式。

五、要求較高的抽象性。若是節點和葉子有不少差別性的話,好比不少方法和屬性都不同,不適合使用組合模式。


p.s. 全部代碼和筆記都可在 個人GitHub 中獲取,若是對您有幫助的話,能夠點個 star 支持一下 🙈

相關文章
相關標籤/搜索