設計模式-結構型-08-組合模式

文章目錄

    • 1、學校院系展示需求
    • 2、組合模式基本介紹
    • 3、組合模式示例
      • 3.1、 解決學校院系展示(透明模式1)
      • 3.2、高考的科目(透明模式2)
      • 3.3、高考的科目(安全組合模式)
    • 4、JDK 源碼分析
    • 5、注意事項和細節

1、學校院系展示需求

編寫程序展示一個學校院系結構:

需求是這樣,要在一個頁面中展示出學校的院系組成,一個學校有多個學院,一個學院有多個系。如圖:
在這里插入圖片描述
傳統方式解決學校院系展示(類圖)

在這里插入圖片描述
問題分析

  • 1)將學院看做是學校的子類,系是學院的子類,這樣實際上是站在組織大小來進行分層次的
  • 2)實際上我們的要求是:在一個頁面中展示出學校的院系組成,一個學校有多個學院,一個學院有多個系。因此這種方案,不能很好實現的 管理 的操作,比如對學院、系的添加、刪除、遍歷等
  • 3)解決方案:把學校、院、系都看做是組織結構,他們之間沒有繼承的關系,而是一個樹形結構,可以更好的實現管理操作 ==> 組合模式

2、組合模式基本介紹

  • 1)組合模式(Composite Pattern),又叫部分整體模式。它創建了對象組的樹形結構,將對象組合成樹狀結構以表示“整體-部分”的層次關系

  • 2)組合模式依據樹形結構來組合對象,用來表示部分以及整體層次

  • 3)這種類型的設計模式屬于結構型模式

  • 4)組合模式使得用戶對單個對象和組合對象的訪問具有一致性,即:組合能讓客戶以一致的方式處理個別對象以及組合對象
    在這里插入圖片描述
    對原理結構圖的說明一即組合模式的角色及職責

  • 1)Component:這是組合中對象聲明接口。在適當情況下,實現所有類共有的接口默認行為,用于訪問和管理 Component子部件。Component可以是抽象類或者接口

  • 2)Leaf:在組合中表示葉子結點,葉子結點沒有子節點

  • 3)Composite:非葉子結點,用于存儲子部件,在Component接口中實現子部件的相關操作。比如增加、刪除

解決的問題

組合模式解決這樣的問題,當我們的要處理的對象可以生成一棵樹形結構,而我們要對樹上的節點和葉子進行操作時,它能夠提供一致的方式,而不用考慮它是節點還是葉子

在這里插入圖片描述

3、組合模式示例

組合模式有兩種寫法,分別是透明模式安全模式

3.1、 解決學校院系展示(透明模式1)

UML 類圖
在這里插入圖片描述

核心代碼

// Component 抽象類
public abstract class OrganizationComponent {private String name;public OrganizationComponent(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public void add(OrganizationComponent organizationComponent) {throw new UnsupportedOperationException();}public void remove(OrganizationComponent organizationComponent) {throw new UnsupportedOperationException();}public abstract void print();
}
// Composite 非葉子節點
public class University extends OrganizationComponent {List<OrganizationComponent> organizationComponentList = new ArrayList<>();public University(String name) {super(name);}@Overridepublic void add(OrganizationComponent organizationComponent) {organizationComponentList.add(organizationComponent);}@Overridepublic void remove(OrganizationComponent organizationComponent) {organizationComponent.remove(organizationComponent);}@Overridepublic void print() {for (OrganizationComponent organizationComponent : organizationComponentList) {organizationComponent.print();}}
}
public class College extends OrganizationComponent {List<OrganizationComponent> organizationComponentList = new ArrayList<>();public College(String name) {super(name);}@Overridepublic void add(OrganizationComponent organizationComponent) {organizationComponentList.add(organizationComponent);}@Overridepublic void remove(OrganizationComponent organizationComponent) {organizationComponent.remove(organizationComponent);}@Overridepublic void print() {System.out.println("=============" + getName() + "=============");for (OrganizationComponent organizationComponent : organizationComponentList) {organizationComponent.print();}}
}
// Leaf 葉子結點
public class Major extends OrganizationComponent {public Major(String name) {super(name);}@Overridepublic void print() {System.out.println(getName());}
}
// 客戶端
public class Client {public static void main(String[] args) {//大學OrganizationComponent university = new University("清華大學");//學院OrganizationComponent computerCollege = new College("計算機學院");OrganizationComponent infoEngineerCollege = new College("信息工程學院");//專業computerCollege.add(new Major("軟件工程"));computerCollege.add(new Major("網絡工程"));computerCollege.add(new Major("計算機科學與技術"));infoEngineerCollege.add(new Major("通信工程"));infoEngineerCollege.add(new Major("信息工程"));university.add(computerCollege);university.add(infoEngineerCollege);university.print();}
}

打印結果

  //=============計算機學院=============//軟件工程//網絡工程//計算機科學與技術//=============信息工程學院=============//通信工程//信息工程

3.2、高考的科目(透明模式2)

1、首先建立一個頂層的抽象科目類,這個類中定義了三個通用操作方法,但是均默認不支持操作

package com.zwx.design.pattern.composite.transparency;/*** 頂層抽象組件*/
public abstract class GkAbstractCourse {public void addChild(GkAbstractCourse course) {System.out.println("不支持添加操作");}public String getName() throws Exception {throw new Exception("不支持獲取名稱");}public void info() throws Exception {throw new Exception("不支持查詢信息操作");}
}

PS:這個類中的公共方法之所以不定義為抽象方法的原因是因為假如定義為抽象方法,那么所有的子類都必須重寫父類方法,這樣體現不出差異性。而這種通過拋異常的方式,如果子類需要用到的功能就重寫覆蓋父類方法即可。

2、新建一個普通科目類繼承通用科目抽象類,這個類作為葉子節點,沒有重寫addChild方法,也就是這個類屬于葉子節點,不支持添加子節點:

package com.zwx.design.pattern.composite.transparency;/*** 普通科目類(葉子節點)*/
public class CommonCource extends GkAbstractCourse {private String name;private String score;public CommonCource(String name, String score) {this.name = name;this.score = score;}@Overridepublic String getName() {return this.name;}@Overridepublic void info() {System.out.println("課程:" + this.name + ",分數:" + score);}
}

3、建立一個具有層級的節點,三個方法都重寫了,支持添加子節點,這個類里面為了方便打印的時候看出層級關系,所以我定義了一個層級屬性。

package com.zwx.design.pattern.composite.transparency;import java.util.ArrayList;
import java.util.List;/*** 樹枝節點*/
public class LevelCource extends GkAbstractCourse {private List<GkAbstractCourse> courseList = new ArrayList<>();private String name;private int level;public LevelCource(String name, int level) {this.name = name;this.level = level;}@Overridepublic void addChild(GkAbstractCourse course) {courseList.add(course);}@Overridepublic String getName() {return this.name;}@Overridepublic void info() throws Exception {System.out.println("課程:" + this.name);for (GkAbstractCourse course : courseList) {for (int i = 0; i < level; i++) {System.out.print(" ");}System.out.print(">");course.info();}}
}

4、建立一個測試類來測試一下:

package com.zwx.design.pattern.composite.transparency;public class TestTransparency {public static void main(String[] args) throws Exception {GkAbstractCourse ywCourse = new CommonCource("語文", "150");GkAbstractCourse sxCourse = new CommonCource("數學", "150");GkAbstractCourse yyCourse = new CommonCource("英語", "150");GkAbstractCourse wlCourse = new CommonCource("物理", "110");GkAbstractCourse hxCourse = new CommonCource("化學", "100");GkAbstractCourse swCourse = new CommonCource("生物", "90");GkAbstractCourse lzCourse = new LevelCource("理綜", 2);lzCourse.addChild(wlCourse);lzCourse.addChild(hxCourse);lzCourse.addChild(swCourse);GkAbstractCourse gkCourse = new LevelCource("理科高考科目", 1);gkCourse.addChild(ywCourse);gkCourse.addChild(sxCourse);gkCourse.addChild(yyCourse);gkCourse.addChild(lzCourse);gkCourse.info();}
}

輸出結果:

課程:理科高考科目  
> 課程:語文,分數:150  
> 課程:數學,分數:150  
> 課程:英語,分數:150  
> 課程:理綜  >課程:物理,分數:110  >課程:化學,分數:100  >課程:生物,分數:90

這里如果用普通科目去調用add方法就會拋出異常,假如上面調用:

swCourse.addChild(ywCourse);

會輸出

不支持添加操作

因為在普通科目類里面并沒有重寫addChild方法。

透明組合模式的缺陷

透明模式的特點就是將組合對象所有的公共方法都定義在了抽象組件內,這樣做的好處是客戶端無需分辨當前對象是屬于樹枝節點還是葉子節點,因為它們具備了完全一致的接口,不過缺點就是葉子節點得到到了一些不屬于它的方法,比如上面的addChild方法,這違背了接口隔離性原則

3.3、高考的科目(安全組合模式)

安全組合模式只是規定了系統各個層次的最基礎的一致性行為,而把組合(樹節點)本身的方法(如樹枝節點管理子類的addChild等方法)放到自身當中。

1、首先還是建立一個頂層的抽象根節點(這里面只定義了一個通用的抽象info方法):

package com.zwx.design.pattern.composite.safe;package com.zwx.design.pattern.composite.safe;/*** 頂層抽象組件*/
public abstract class GkAbstractCourse {protected String name;protected String score;public GkAbstractCourse(String name, String score) {this.name = name;this.score = score;}public abstract void info();
}

2、建立一個葉子節點(這里只是重寫了info方法,沒有定義其他特有方法):

package com.zwx.design.pattern.composite.safe;/*** 葉子節點*/
public class CommonCource extends GkAbstractCourse {public CommonCource(String name, String score) {super(name, score);}@Overridepublic void info() {System.out.println("課程:" + this.name + ",分數:" + this.score);}
}

3、定義一個樹枝節點(這個類當中定義了一個樹枝特有的方法addChild):

package com.zwx.design.pattern.composite.safe;import java.util.ArrayList;
import java.util.List;/*** 樹枝節點*/
public class LevelCource extends GkAbstractCourse {private List<GkAbstractCourse> courseList = new ArrayList<>();private int level;public LevelCource(String name, String score, int level) {super(name, score);this.level = level;}public void addChild(GkAbstractCourse course) {courseList.add(course);}@Overridepublic void info() {System.out.println("課程:" + this.name + ",分數:" + this.score);for (GkAbstractCourse course : courseList) {for (int i = 0; i < level; i++) {System.out.print(" ");}System.out.print(">");course.info();}}
}

4、新建測試類來測試:

package com.zwx.design.pattern.composite.safe;public class TestSafe {public static void main(String[] args) throws Exception {CommonCource ywCourse = new CommonCource("語文", "150");CommonCource sxCourse = new CommonCource("數學", "150");CommonCource yyCourse = new CommonCource("英語", "150");CommonCource wlCourse = new CommonCource("物理", "110");CommonCource hxCourse = new CommonCource("化學", "100");CommonCource swCourse = new CommonCource("生物", "90");LevelCource lzCourse = new LevelCource("理綜", "300", 2);lzCourse.addChild(wlCourse);lzCourse.addChild(hxCourse);lzCourse.addChild(swCourse);LevelCource gkCourse = new LevelCource("理科高考", "750", 1);gkCourse.addChild(ywCourse);gkCourse.addChild(sxCourse);gkCourse.addChild(yyCourse);gkCourse.addChild(lzCourse);gkCourse.info();}
}

這里和透明方式不一樣,葉子節點不具備addChild功能,所以無法調用,而上面的示例中時可以被調用,但是調用之后顯示不支持,這就是這兩種寫法最大的區別。

組合模式角色

從上面示例中,可以看到組合模式包含了以下三個角色:

  • 抽象根節點(Component):定義系統各層次對象的公有屬性和方法,可以預先定義一些默認行為和屬性。
  • 樹枝節點(Composite):定義樹枝節點的行為,存儲子節點,組合樹枝節點和葉子節點形成一個樹形結構。
  • 葉子節點(Leaf):是系統遍歷層次中的最小單位,下面沒有子節點。

4、JDK 源碼分析

Java 的集合類—— HashMap 就使用了組合模式

UML 類圖

在這里插入圖片描述
核心代碼

// Component
public interface Map<K,V> {interface Entry<K,V> {}
}
public abstract class AbstractMap<K,V> implements Map<K,V> {}
// Composite
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {// Leafstatic class Node<K,V> implements Map.Entry<K,V> {}
}

說明

  • 1)Map 就是一個抽象的構建,類似Component
  • 2)HashMap 是一個中間的構建,類似Composite,實現 / 繼承了相關方法 put、putAll
  • 3)Node 是 HashMap 的靜態內部類,類似Leaf葉子節點,這里就沒有 put

5、注意事項和細節

  • 1)簡化客戶端操作:客戶端只需要面對一致的對象,而不用考慮整體部分或者節點葉子的問題
  • 2)具有較強擴展性:當我們要更改組合對象時,我們只需要調整內部的層次關系,客戶端不用做出任何改動
  • 3)方便創建復雜的層次結構:客戶端不用理會組合里面的組成細節,容易添加節點或者葉子,從而創建出復雜的樹形結構
  • 4)需要遍歷組織機構,或者處理的對象具有樹形結構時,非常適合使用組合模式
  • 5)要求較高的抽象性,如果節點和葉子有很多差異性的話,比如很多方法和屬性都不一樣,不適合使用組合模式

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/42784.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/42784.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/42784.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

存儲過程編程-創建(CREATE PROCEDURE)、執行(EXEC)、刪除(DROP PROCEDURE)

一、定義 1、存儲過程是在SQL服務器上存儲的已經編譯過的SQL語句組。 2、存儲過程分為三類&#xff1a;系統提供的存儲過程、用戶定義的存儲過程和擴展存儲過程 &#xff08;1&#xff09;系統提供的存儲過程&#xff1a;在安裝SQL Server時&#xff0c;系統創建了很多系統存…

AI機器人在企業拓客上常見的功能有哪些

AI機器人具備多種功能&#xff0c;這些功能主要基于其被設計和訓練的目的。整理了一些常見的AI機器人功能&#xff1a; 1. 語音識別與自然語言處理&#xff1a; - 語音識別&#xff1a;將用戶的語音輸入轉換為文本&#xff0c;以便機器人可以理解和處理。 - 自然語言處理…

QCC5181 歌詞歌曲名多國語言顯示替代QCC5125 CSR8675

QCC518X作為Qualcomm新一代藍牙技術芯片&#xff0c;支持最新藍牙協議V5.4&#xff0c;較QCC512X系列&#xff0c;它有更強大的DSP、CPU。除支持USB、I2S、SPDIF等接口外&#xff0c;還擴展了LE Audio功能&#xff0c;擴展支持AptX Lossless。以5181為例&#xff0c;我們還擴展…

vscode語言模式

1.背景 寫vue3ts項目的時候&#xff0c;用到了volar插件&#xff0c;在單文件使用的時候&#xff0c;鼠標懸浮在代碼上面會有智能提示&#xff1b; 但是最近volar插件提示被棄用了&#xff0c;然后我按照它的官方提示&#xff0c;安裝了Vue-official擴展插件&#xff0c;但是…

Banana Pi BPI-M5 Pro 低調 SBC 采用 Rockchip RK3576 八核 Cortex-A72/A53 AIoT SoC

Banana Pi BPI-M5 Pro&#xff0c;也稱為 Armsom Sige5&#xff0c;是一款面向 AIoT 市場的低調單板計算機 (SBC)&#xff0c;由 Rockchip RK3576 八核 Cortex-A72/A53 SoC 驅動&#xff0c;提供Rockchip RK3588和RK3399 SoC 之間的中檔產品。 該主板默認配備 16GB LPDDR4X 和…

如何大幅減少 Vue.js 中的包大小和加載時間,提升用戶體驗!

大家好,我是CodeQi! 一位熱衷于技術分享的碼仔。 你知道嗎,根據Google 的一項研究,如果網站加載時間超過 3 秒,53% 的移動用戶會離開該網站? 性能優化是一個經常討論的話題,但很多開發人員并不關心提高應用的速度。 在前端開發中,優化包大小和加載時間對于提升用戶體…

下一代 CLI 工具,使用Go語言用于構建令人驚嘆的網絡應用程序

大家好&#xff0c;今天給大家分享一個創新的命令行工具Gowebly CLI&#xff0c;它專注于使用Go語言來快速構建現代Web應用程序。 Gowebly CLI 是一款免費開源軟件&#xff0c;有助于在后端使用 Go、在前端使用 htmx 和 hyperscript 以及最流行的 CSS 框架輕松構建令人驚嘆的 W…

入門PHP就來我這(高級)15 ~ 圖書刪除功能

有膽量你就來跟著路老師卷起來&#xff01; -- 純干貨&#xff0c;技術知識分享 路老師給大家分享PHP語言的知識了&#xff0c;旨在想讓大家入門PHP&#xff0c;并深入了解PHP語言。 今天給大家接著上篇文章實現圖書刪除功能&#xff0c;來實現刪除圖書信息記錄行的功能。 1 刪…

高顏值官網(3):家居用品網站12個,好的創意都在這里。

hello&#xff0c;大家好&#xff0c;我是大千UI工場&#xff0c;本文為大家帶來家居用品網站UI&#xff0c;供大家欣賞。

項目代碼優化(1)——下單邏輯

給一個電商開發的系統排查&#xff0c;發現漏洞很多。很多經驗不夠的開發者很容易忽視的邏輯錯誤陷阱。在給一個項目做二次開發時候&#xff0c;檢測到的相關經典案例。這里整理支付和產品相關的邏輯&#xff0c;方便后續查看。&#xff0c;這里進行一些簡單的邏輯漏洞梳理與修…

Ubuntu 22.04 LTS 上安裝 MySQL8.0.23(在線安裝)

目錄 在線安裝MySQL 步驟1&#xff1a;更新軟件包列表 步驟2&#xff1a;安裝MySQL服務器 步驟3&#xff1a;啟動MySQL服務 步驟4&#xff1a;檢查MySQL狀態 步驟5&#xff1a;修改密碼、權限 在線安裝MySQL 步驟1&#xff1a;更新軟件包列表 在進行任何軟件安裝之前&a…

p9函數(1)

int Add(int x,int y) { int z0; zxy; return z; } int main() { int a10; int b20; int sumAdd(a,b); printf("%d\n",sum); return 0; } 字符串求長度 int main() { char arr1[]"bit"; char arr2[20]"###…

移動UI: 什么特征會被認為是簡潔風格,用案例告訴你

什么是簡潔風格&#xff0c;恐怕一百個人有一百個是理解&#xff0c;本文通過理論分析案例的方式進行探討。 移動 UI 中的簡潔風格通常具有以下幾個特征&#xff1a; 1. 平面化設計&#xff1a; 簡潔風格的移動 UI 善于運用平面化設計&#xff0c;即去除過多的陰影、漸變和立…

水冷液冷負載系統的六種基本類型

您可以選擇六種基本類型的冷卻系統&#xff0c;以滿足負載的冷卻需求。每個人都有其優點和缺點。本文旨在識別不同類型的冷卻系統并確定它們的優缺點&#xff0c;以便您可以根據自己的需求做出明智的選擇。 液體冷卻系統有六種基本類型&#xff1a; 1.液對液 2.閉環干燥系統…

聚類標簽的藝術:SKlearn中的數據聚類標簽分配策略

聚類標簽的藝術&#xff1a;SKlearn中的數據聚類標簽分配策略 在機器學習領域&#xff0c;聚類是一種無監督學習方法&#xff0c;旨在將數據集中的樣本劃分為若干個簇&#xff0c;使得同一簇內的樣本相似度高&#xff0c;而不同簇之間的樣本相似度低。聚類標簽分配是聚類過程中…

深度講解 UUID/GUID 的結構、原理以及生成機制

目錄 一. 前言 二. 被廣泛使用 三. UUID 的結構 3.1. 必須了解的 3.2. 十六進制數字字符&#xff08;hexDigit&#xff09; 3.3. UUID 基本結構 3.4. 類型&#xff08;變體&#xff09;和保留位 3.5. 版本&#xff08;子類型&#xff09; 3.6. 時間戳 3.7. 時鐘序列 …

管理《歐盟數字服務法》交易者要求

《數字服務法》合規性 根據《數字服務法》(DSA) 的要求&#xff0c;對于在歐盟地區 (EU) 通過 App Store 分發 App 的所有交易商&#xff0c;Apple 需要驗證并顯示其聯系信息。請指明你是否將以交易商或非交易商的身份在歐盟地區分發任何內容。進一步了解你是否應為交易商。 …

[激光原理與應用-101]:南京科耐激光-激光焊接-焊中檢測-智能制程監測系統IPM介紹 - 5 - 3C行業應用 - 電子布局類型

目錄 前言&#xff1a; 一、激光在3C行業的應用概述 1.1 概述 1.2 激光焊接在3C-電子行業應用 二、3C電子行業中激光焊接 2.1 紐扣電池 2.2 均溫板 2.3 指紋識別器 2.4 攝像頭模組 2.5 IC芯片切割 三、3C行業中激光切割 四、激光在3C行業中的其他應用 4.1 涂層去除…

Golang | Leetcode Golang題解之第222題完全二叉樹的節點個數

題目&#xff1a; 題解&#xff1a; func countNodes(root *TreeNode) int {if root nil {return 0}level : 0for node : root; node.Left ! nil; node node.Left {level}return sort.Search(1<<(level1), func(k int) bool {if k < 1<<level {return false}…

包裝工程期刊

《包裝工程》&#xff08;Packaging Engineering&#xff09;創刊于1980年&#xff0c;原刊名為《防腐包裝》&#xff0c;由聶榮臻元帥親筆題寫。主管單位為中國兵器裝備集團有限公司&#xff0c;主辦單位為西南技術工程研究所&#xff0c;出版單位為《包裝工程》編輯部。目前期…