結構型模式:組合模式

文章首發:
結構型模式:組合模式編程

夜晚

七大結構型模式之三:組合模式。設計模式

簡介

姓名 :組合模式安全

英文名 :Composite Pattern微信

價值觀 :專門解決各類樹形疑難雜症架構

我的介紹
Compose objects into tree structures to represent part-whole hierarchies.Composite lets clients treat individual objects and compositions of objects uniformly.
將對象組合成樹形結構以表示「部分-總體」的層次結構,使得用戶對單個對象和組合對象的使用具備一致性。
(來自《設計模式之禪》)機器學習

你要的故事

今天我們再講講我們程序猿的組織架構。技術類的組織架構比較單一,基本上都是這樣:經理--->組長--->工程師,以下圖所示。ide

IT組織架構

各個公司的 title 可能不太同樣,可是基本是差很少這種架構,按職業發展,從入職到能獨立開發需求便爲工程師,從獨立開發需求到能帶小團隊開發便爲組長,從帶小團隊開發到能帶幾個團隊一塊兒協做開發便爲經理。學習

假設目前有一家公司,技術部就 4 我的,大熊擔任經理,中熊擔任組長,小熊1和小熊2擔任工程師。下面的代碼都圍繞這個假設編寫。測試

非組合模式

咱們先來一個非正常的實現方案:從組織架構裏,有 3 個角色,分別是經理、組長、工程師,那麼咱們就按角色去實現一番。this

Manager 爲經理類,經理下有多個組長 leaders。

/**
 * 經理
 */
class Manager {

    private String name;
    private List<Leader> leaders;

    public Manager(String name) {
        this.name = name;
        this.leaders = new LinkedList<>();
    }

    public void add(Leader leader) {
        this.leaders.add(leader);
    }

    public void remove(Leader leader) {
        this.leaders.remove(leader);
    }

    public void display(int index) {
        for (int i = 0; i < index; i++) {
            System.out.print("----");
        }
        System.out.println("經理:" + this.name);
        leaders.forEach(leader -> {
            leader.display(index+1);
        });
    }

}

Leader 爲組長類,組長下有多個工程師 engineers。

/**
 * 組長
 */
class Leader {

    private String name;
    private List<Engineer> engineers;

    public Leader(String name) {
        this.name = name;
        this.engineers = new LinkedList<>();
    }

    public void add(Engineer engineer) {
        this.engineers.add(engineer);
    }

    public void remove(Engineer engineer) {
        this.engineers.remove(engineer);
    }

    public void display(int index) {
        for (int i = 0; i < index; i++) {
            System.out.print("----");
        }
        System.out.println("組長:" + this.name);
        engineers.forEach(engineer -> {
            engineer.display(index + 1);
        });
    }
}

Engineer 爲工程師類,工程師沒有下屬。

/**
 * 工程師
 */
class Engineer {

    private String name;

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

    public void display(int index) {
        for (int i = 0; i < index; i++) {
            System.out.print("----");
        }
        System.out.println("工程師:" + this.name);
    }

}

測試代碼

public class NoCompositeTest {

    public static void main(String[] args) {
        Manager manager = new Manager("大熊");
        Leader leader = new Leader("中熊");
        Engineer engineer1= new Engineer("小熊1");
        Engineer engineer2 = new Engineer("小熊2");

        manager.add(leader);
        leader.add(engineer1);
        leader.add(engineer2);

        manager.display(0);
    }

}

打印結果:
經理:大熊
----組長:中熊
--------工程師:小熊1
--------工程師:小熊2

這份代碼看完以後,有什麼想法?是否是感受代碼有點冗餘?經理和組長的代碼幾乎一致,而工程師類和經理類、組長類也有共同點,惟一的區別就是工程師沒有下屬,所以沒有對下屬的增刪操做方法。

安全模式

經過上面一層思考,這 3 個角色有相通性,咱們能夠抽象出一個 Employee2 類,把 3 個角色共同的特性放到 Employee2 類中,經理和組長合併共用一個類,由於在這個例子裏,這 2 個角色徹底同樣的。下面看代碼。

Employee2 抽象類,它有這 3 個角色共有的特性,名稱設置獲取以及顯示數據。

abstract class Employee2 {

    private String name;

    public String getName() {
        return name;
    }

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

    public abstract void display(int index);

}

Leader2 領導類,把上面的經理類和組長類都合併到這個領導類,由於他們都是領導層。

class Leader2 extends Employee2 {

    private List<Employee2> employees;

    public Leader2(String name) {
        this.setName(name);
        this.employees = new ArrayList<>();
    }

    public void add(Employee2 employee) {
        this.employees.add(employee);
    }

    public void remove(Employee2 employee) {
        this.employees.remove(employee);
    }

    @Override
    public void display(int index) {
        for(int i = 0; i < index; i++) {
            System.out.print("----");
        }
        System.out.println("領導:" + this.getName());
        this.employees.forEach(employee -> {
            employee.display(index + 1);
        });
    }
}

Engineer2 工程師類,工程師類比較簡單,由於名稱設置獲取在抽象類 Employee2 有了,因此就只需實現顯示數據的功能。

class Engineer2 extends Employee2 {

    public Engineer2(String name) {
        this.setName(name);
    }

    @Override
    public void display(int index) {
        for(int i = 0; i < index; i++) {
            System.out.print("----");
        }
        System.out.println("工程師:" + this.getName());
    }
}

測試代碼

public class CompositeTest {

    public static void main(String[] args) {
        // 安全模式
        Leader2 leader1 = new Leader2("大熊");
        Leader2 leader2 = new Leader2("中熊");
        Engineer2 engineer1 = new Engineer2("小熊1");
        Engineer2 engineer2 = new Engineer2("小熊2");

        leader1.add(leader2);
        leader2.add(engineer1);
        leader2.add(engineer2);

        leader1.display(0);
    }

}

打印結果:
領導:大熊
----領導:中熊
--------工程師:小熊1
--------工程師:小熊2

看下運行結果和上面是一致的,這份代碼比第一份代碼有更好的封裝性,也更符合面向對象的編程方式,經理和組長被合併成 Leader2,也就是我們今天講的組合模式,Leader2 爲組合對象。上面講的是安全模式,安全模式指的是抽象類 Employee2 只提供了 3 個角色中共有的特性,安全是相對透明模式所說的,由於這裏領導類 Leader2 和工程師類 Engineer2 都只提供了本身能提供的方法,Engineer2 不會有多餘的方法,而透明模式則不是。下面講講透明模式。

透明模式

透明模式把組合對象(即領導類)使用的方法放到抽象類中,而由於工程師沒有下屬,則不具體實現對應的方法。代碼以下。

Employee3 抽象類,將組合對象的屬性 employees 和 方法 add()remove() 都放到這個類裏面。

abstract class Employee3 {

    private String name;
    private List<Employee3> employees;

    public String getName() {
        return name;
    }

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

    public List<Employee3> getEmployees() {
        return employees;
    }

    public void setEmployees(List<Employee3> employees) {
        this.employees = employees;
    }

    public abstract void add(Employee3 employee);

    public abstract void remove(Employee3 employee);

    public abstract void display(int index);

}

Leader3 領導類,具體實現 Employee3 提供的全部方法。

class Leader3 extends Employee3 {

    public Leader3(String name) {
        this.setName(name);
        this.setEmployees(new ArrayList<>());
    }

    @Override
    public void add(Employee3 employee) {
        this.getEmployees().add(employee);
    }

    @Override
    public void remove(Employee3 employee) {
        this.getEmployees().remove(employee);
    }

    @Override
    public void display(int index) {
        for(int i = 0; i < index; i++) {
            System.out.print("----");
        }
        System.out.println("領導:" + this.getName());
        this.getEmployees().forEach(employee -> {
            employee.display(index + 1);
        });
    }
}

Engineer3 工程師類,只具體實現 Employee3 中的 display() 方法,add()remove() 方法不是工程師具有的,因此留空,不作具體實現。

class Engineer3 extends Employee3 {

    public Engineer3(String name) {
        this.setName(name);
    }

    @Override
    public void add(Employee3 employee) {
        // 沒有下屬
    }

    @Override
    public void remove(Employee3 employee) {
        // 沒有下屬
    }

    @Override
    public void display(int index) {
        for(int i = 0; i < index; i++) {
            System.out.print("----");
        }
        System.out.println("工程師:" + this.getName());
    }
}

測試代碼:

public class CompositeTest {

    public static void main(String[] args) {
        // 透明模式
        Leader3 leader3 = new Leader3("大熊");
        Leader3 leader31 = new Leader3("中熊");
        Engineer3 engineer31 = new Engineer3("小熊1");
        Engineer3 engineer32 = new Engineer3("小熊2");

        leader3.add(leader31);
        leader31.add(engineer31);
        leader31.add(engineer32);

        leader3.display(0);

    }

打印結果:
領導:大熊
----領導:中熊
--------工程師:小熊1
--------工程師:小熊2
}

安全模式把 3 個角色的共同點抽象到 Employee2 中,透明模式則把 3 個角色中的領導者(組合對象)的內容抽象到 Employee3 中。透明模式有些很差的地方在於工程師也有領導者的下屬對象和相應的方法,其實工程師並無這些功能。安全模式把領導者和工程師分開,每一個對象都只提供本身具備的功能,這樣子在使用的時候也就更安全。

總結

咱們根據 IT 組織架構,從簡單的每一個角色對應一個類的實現,再到抽象出每一個角色共同的功能、組合領導類的安全模式,接着再到抽象起來領導類(組合)全部功能的透明模式,分析了組合模式的完整過程,也講了安全模式和透明模式的差別。組合模式讓對象更加有層次,將對象的劃分更加清晰,特別是樹形結構的層次,利用組合模式會更加簡化。

推薦閱讀

結構型模式:橋接模式

結構型模式:適配器模式

行爲型模式:解釋器模式

公衆號後臺回覆『大禮包』獲取 Java、Python、IOS 等教程
加我的微信備註『教程』獲取架構師、機器學習等教程

LieBrother

相關文章
相關標籤/搜索