結構型模式:組合模式

来源:https://www.cnblogs.com/liebrother/archive/2019/04/24/10760440.html
-Advertisement-
Play Games

文章首發: "結構型模式:組合模式" 七大結構型模式之三:組合模式。 簡介 姓名 :組合模式 英文名 :Composite Pattern 價值觀 :專門解決各種樹形疑難雜症 個人介紹 : Compose objects into tree structures to represent part ...


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

夜晚

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

簡介

姓名 :組合模式

英文名 :Composite Pattern

價值觀 :專門解決各種樹形疑難雜症

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

你要的故事

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

IT組織架構

各個公司的 title 可能不太一樣,但是基本是差不多這種架構,按職業發展,從入職到能獨立開發需求便為工程師,從獨立開發需求到能帶小團隊開發便為組長,從帶小團隊開發到能帶幾個團隊一起協作開發便為經理。

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

非組合模式

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

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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天練習一個小demo, 從本地讀取圖片, 然後實現類似淘寶放大鏡的效果, 再加兩個需求 1 .可以調節縮放比例,預設放大兩倍 2 . 圖片寬高自適應, 不固定寬高 話不多說先看效果: 原理:1, 右側放大區域的大小等於左側半透明滑塊大小乘以縮放倍數 2, 右側放大區域圖片的原始尺寸要和 左側圖片一 ...
  • <html><body> <h3>js控制文件上傳數量</h3> <form action="" enctype="multipart/form-data"> <input type="file" name="file" multiple="multiple" onchange="fileCount ...
  • 一、什麼是小程式? 基於微信的可以為用戶提供一些服務的web項目,利用微信提供的介面可以讓所有開發者使用到微信的原生能力,去完成一些之前做不到或者難以做到的事情。 二、小程式開發工具以及語言? 小程式需要用到微信提供的小程式開發工具,​小程式的主要開發語言是 JavaScript 。 三、小程式與普 ...
  • 項目中經常遇到要選擇城市。用到三級聯動的方式 微信小程式的 組件 是三級聯動的,但是無法自定義,這讓我們心痛不已,值得我們欣慰的 picker view 組件是可以自定義添加多個選項,但還是無法聯動。既然這樣那就自己寫一個聯動。 做到如下圖所示: 分為動態獲取地址 引用靜態文件獲取地址 <! mor ...
  • 轉自:https://www.cnblogs.com/kidsitcn/p/7182274.html 比例尺函數是這樣的javascript函數: 接收通常是數字,日期,類別等data輸入並且: 返回一個代表可視化元素的值,比如坐標,顏色,長度或者半徑等 比例尺通常用於變換(或者說映射)抽象的數據值 ...
  • 做法就是使用iframe標簽 1.text,pdf的文件預覽 <iframe class="filename" :src="文件的地址" width='100%' height='600' frameborder='1' ></iframe> 2.doc,xls,ppt等office的預覽 <ifr ...
  • 一、對象的擴展 1.1對象屬性名錶達式 ES6可以在JSON中使用[]包裹一個key的名字。此時這個key將用表達式作為屬性名(被當做變數求值),這個key值必須是字元串。 1.2 Object.assign()方法 該方法用於對象的合併,將源對象的所有可枚舉的屬性,複製到目標對象。 Object. ...
  • 譯者按: 為什麼偏要用 符號? 原文 : "JavaScript's new private class fields" 譯者 : "Fundebug" 本文采用意譯,版權歸原作者所有 "proposal class fields" 與 "proposal private methods" 定義了 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...