【设计模式】组合模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )
文章目錄
- 一、組合模式簡介
- 二、組合模式適用場景
- 三、組合模式優(yōu)缺點(diǎn)
- 四、組合模式和訪問者模式
- 五、組合模式代碼示例
- 1、書籍和目錄的抽象父類
- 2、書籍類
- 3、目錄類
- 4、測試類
一、組合模式簡介
組合模式 : 將 對象 組合成 樹形結(jié)構(gòu) , 表示 " 部分-整體 " 層次結(jié)構(gòu) ;
組合模式 使 客戶端 對 單個(gè)對象 和 組合對象 保持一致的 方式處理 ;
如 : 文件系統(tǒng) , 根目錄下有若干文件和目錄 , 在二級(jí)目錄下還有目錄和文件 , 這種情況下 , 適合使用組合模式 ;
組合模式類型 : 結(jié)構(gòu)型
二、組合模式適用場景
組合模式適用場景 :
- 忽略差異 : 希望 客戶端 可以 忽略 組合對象 與 單個(gè)對象 的差異 ;
- 處理樹形結(jié)構(gòu) ;
三、組合模式優(yōu)缺點(diǎn)
組合模式優(yōu)點(diǎn) :
- 定義層次 : 清楚地 定義 分層次 的 復(fù)雜對象 , 表示 對象 的 全部 或 部分 層次 ;
- 忽略層次 : 讓 客戶端 忽略 層次之間的差異 , 方便對 整個(gè)層次結(jié)構(gòu) 進(jìn)行控制 ;
- 簡化客戶端代碼 ;
- 符合開閉原則 ;
組合模式缺點(diǎn) :
- 限制類型復(fù)雜 : 限制類型時(shí) , 比較復(fù)雜 ;
如 : 某個(gè)目錄中只能包含文本文件 , 使用組合模式時(shí) , 不能依賴類型系統(tǒng) , 施加約束 , 它們都來自于節(jié)點(diǎn)的抽象層 ; 在這種情況下 , 必須通過在運(yùn)行時(shí)進(jìn)行類型檢查 , 這樣就變得比較復(fù)雜 ; - 使設(shè)計(jì)變得更加抽象 ;
四、組合模式和訪問者模式
組合模式和訪問者模式 : 兩個(gè)模式經(jīng)常結(jié)合起來使用 , 使用 訪問者模式 , 訪問 組合模式 中的 遞歸結(jié)構(gòu) ,
五、組合模式代碼示例
業(yè)務(wù)邏輯 :
書籍 分屬于 目錄 下 , 如果使 書籍目錄 和 書籍 繼承同一個(gè)抽象類 ( 目錄組件 ) , 可以將 書籍 及 由書籍組成的書籍目錄 當(dāng)做同一個(gè)類型的對象進(jìn)行操作 , 操作上的具體的差別 , 進(jìn)行定制化處理 ;
1、書籍和目錄的抽象父類
抽象類中所有的方法 都拋出異常 , 子類重寫需要的方法 , 如果子類實(shí)例對象調(diào)用沒有重寫的方法 , 就會(huì)拋出異常 ;
package composite;/*** 目錄組件* 目錄 和 書籍 都繼承 CatalogComponent 接口* 子類根據(jù)當(dāng)前的的類型 , 選擇性重寫接口*/ public abstract class CatalogComponent {/*** 添加元素* @param catalogComponent*/public void add(CatalogComponent catalogComponent) {throw new UnsupportedOperationException("不支持的操作");}/*** 刪除元素* @param catalogComponent*/public void remove(CatalogComponent catalogComponent) {throw new UnsupportedOperationException("不支持的操作");}/*** 獲取名稱* @param catalogComponent*/public String getName(CatalogComponent catalogComponent) {throw new UnsupportedOperationException("不支持的操作");}/*** 獲取價(jià)格* @param catalogComponent* @return*/public double getPrice(CatalogComponent catalogComponent) {throw new UnsupportedOperationException("不支持的操作");}/*** 如果該組件是目錄 , 直接打印目錄* 如果該組件是書籍 , 直接打印課程*/public void printf() {throw new UnsupportedOperationException("不支持的操作");}}2、書籍類
書籍類 重寫了 CatalogComponent 的 getName / getPrice / printf 方法 , 如果調(diào)用其余方法 , 會(huì)拋出異常 ;
package composite;/*** 書籍類* 重寫了 CatalogComponent 的 getName / getPrice / printf 方法* 如果調(diào)用其余方法 , 會(huì)拋出異常*/ public class Book extends CatalogComponent {/*** 書籍名稱*/private String name;/*** 書籍價(jià)格*/private double price;public Book(String name, double price) {this.name = name;this.price = price;}@Overridepublic String getName(CatalogComponent catalogComponent) {return this.name;}@Overridepublic double getPrice(CatalogComponent catalogComponent) {return this.price;}@Overridepublic void printf() {System.out.println("Book : name = " + name + " , price = " + price);} }3、目錄類
目錄類 重寫了 CatalogComponent 的 getName / add / remove / printf 方法 , 如果調(diào)用其余方法 , 會(huì)拋出異常 ;
package composite;import java.util.ArrayList;/*** 目錄類* 重寫了 CatalogComponent 的 getName / add / remove / printf 方法* 如果調(diào)用其余方法 , 會(huì)拋出異常*/ public class Catalogue extends CatalogComponent {/*** 維護(hù)書籍列表*/private ArrayList<CatalogComponent> items = new ArrayList<>();/*** 書籍名稱*/private String name;/*** 存儲(chǔ)當(dāng)前目錄的層數(shù)* 最外面的是 0 層*/private Integer level;public Catalogue(String name, Integer level) {this.name = name;this.level = level;}@Overridepublic String getName(CatalogComponent catalogComponent) {return this.name;}@Overridepublic void add(CatalogComponent catalogComponent) {items.add(catalogComponent);}@Overridepublic void remove(CatalogComponent catalogComponent) {items.remove(catalogComponent);}@Overridepublic void printf() {System.out.println(this.name + " : ");for (CatalogComponent catalogComponent : items) {// 這樣可以將目錄層次完整的打印出來if (this.level != null) {for (int i = 0; i < level; i++) {System.out.print(" ");}}catalogComponent.printf();}} }4、測試類
package composite;public class Main {public static void main(String[] args) {// 認(rèn)為 書籍 和 目錄 都是 CatalogComponent 類型的CatalogComponent storyBook = new Book("故事書", 2.0);CatalogComponent novelBook = new Book("小說", 8.0);CatalogComponent mathBook = new Book("數(shù)學(xué)書", 7.0);CatalogComponent englishBook = new Book("英語書", 3.0);CatalogComponent schoolBooks = new Catalogue("學(xué)校課本", 2);schoolBooks.add(mathBook);schoolBooks.add(englishBook);// 主目錄 , 包含上述所有內(nèi)容 , 2 本書 和 1 個(gè)目錄CatalogComponent main = new Catalogue("所有書籍", 1);main.add(storyBook);main.add(novelBook);main.add(schoolBooks);// 打印主目錄main.printf();} }
執(zhí)行結(jié)果 :
所有書籍 : Book : name = 故事書 , price = 2.0Book : name = 小說 , price = 8.0學(xué)校課本 : Book : name = 數(shù)學(xué)書 , price = 7.0Book : name = 英語書 , price = 3.0總結(jié)
以上是生活随笔為你收集整理的【设计模式】组合模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【设计模式】代理模式 ( 动态代理 )
- 下一篇: 【设计模式】抽象工厂模式 ( 简介 |