設(shè)計(jì)模式之組合模式

之前做一個(gè)需求,設(shè)計(jì)一個(gè)設(shè)置程序,設(shè)置程序中包含不同的頁面,頁面中又有不同的分組,每個(gè)分組下面又有不同的項(xiàng),每個(gè)項(xiàng)包含不同的控件。

當(dāng)用戶點(diǎn)擊保存的時(shí)候,需要將所有的配置,都映射并保存在配置文件中。

之前做的時(shí)候,是將每個(gè)控件都綁定一個(gè)映射項(xiàng),然后遍歷所有的頁的組,在遍歷組的項(xiàng),再遍歷項(xiàng)的控件調(diào)用保存。

偽代碼如下:

for(Page page:pages){? ? if(page.controls()!=null){? ? ? ? for(Group control:page.controls()){? ? ? ? ? ? //....? ? ? ? }? ? }}

好幾層迭代,每層迭代中還需要判斷是否包含相關(guān)的組

后來,又出現(xiàn)了一個(gè)新的需求,因?yàn)橐推渌绦蚵?lián)動(dòng),因此如果用戶修改了某個(gè)配置,那么應(yīng)該不等用戶點(diǎn)擊保存,就應(yīng)該寫到配置文件中,有點(diǎn)類似于VUE的雙向綁定。

這個(gè)時(shí)候面對這臃腫的代碼,簡直崩潰。

仔細(xì)梳理上面的需求可以發(fā)現(xiàn),由于設(shè)置程序分為好幾個(gè)頁,同時(shí)每個(gè)頁分為幾個(gè)組,每個(gè)組又有不同項(xiàng),每個(gè)項(xiàng)包含不同的控件。可以類比到每個(gè)國家的政治區(qū)域劃分,就好像每個(gè)省包含很多市,每個(gè)市又有不同的縣。而有些地方又有直轄市。因此,我們可以學(xué)習(xí)這種管理方式,讓每個(gè)分支自己管理自己的分組,而作為根節(jié)點(diǎn),我們只用管理根節(jié)點(diǎn)所接觸到的結(jié)構(gòu)即可。

成功優(yōu)化后的代碼,將會(huì)是如下效果:

for(Control page:pages){? ? page.save();}

簡直不能簡單的更多。

以上思想,便是組合模式的雛形。

組合模式將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。組合模式使得用戶可以使用一致的方法操作單個(gè)對象和組合對象。

比如上面的代碼,我們可以首先定義一個(gè)接口:

public interface Control {? ? //添加節(jié)點(diǎn)? ? void add(Control control);? ? //刪除節(jié)點(diǎn)? ? void remove(Control control);? ? //設(shè)置層級,方便打印? ? void setLevel(int level);? ? //保存配置? ? void save();}

然后,依次定義Page , Group , Item

//定義page,group,item等相同public class Page implements Control {? ? private List<Control> children = new ArrayList<>();? ? private int level;? ? @Override? ? public void save() {? ? ? ? System.out.println("- Page");? ? ? ? for (Control control : children) {? ? ? ? ? ? control.save();? ? ? ? }? ? }? ? @Override? ? public void add(Control control) {? ? ? ? control.setLevel(1);? ? ? ? children.add(control);? ? }? ? @Override? ? public void remove(Control control) {? ? ? ? children.remove(control);? ? }? ? @Override? ? public void setLevel(int level) {? ? ? ? this.level=level;? ? }}

//其他相同

接下來,可以定義具體的節(jié)點(diǎn),這樣的節(jié)點(diǎn)在組合模式中稱為”葉子節(jié)點(diǎn)“

public class Button implements? Control {? ? private int level;? ? @Override? ? public void save() {? ? ? ? StringBuilder stringBuilder=new StringBuilder();? ? ? ? for (int i = 0; i < level; i++) {? ? ? ? ? ? stringBuilder.append('-').append(" ");? ? ? ? }? ? ? ? System.out.println(stringBuilder+" Button保存成功");? ? }? ? @Override? ? public void add(Control control) {? ? ? ? System.out.println("錯(cuò)誤的操作,不支持add()");? ? }? ? @Override? ? public void remove(Control control) {? ? ? ? System.out.println("錯(cuò)誤的操作,不支持remove()");? ? }? ? @Override? ? public void setLevel(int level) {? ? ? ? this.level=level;? ? }}

public class TextBox implements Control {? ? private int? level;? ? @Override? ? public void save() {? ? ? ? StringBuilder stringBuilder=new StringBuilder();? ? ? ? for (int i = 0; i < level; i++) {? ? ? ? ? ? stringBuilder.append('-').append(" ");? ? ? ? }? ? ? ? System.out.println(stringBuilder+"TextBox保存成功");? ? }? ? @Override? ? public void add(Control control) {? ? ? ? System.out.println("錯(cuò)誤的操作,不支持add()");? ? }? ? @Override? ? public void remove(Control control) {? ? ? ? System.out.println("錯(cuò)誤的操作,不支持remove()");? ? }? ? @Override? ? public void setLevel(int level) {? ? ? ? this.level=level;? ? }}

到這里,基本就執(zhí)行完了,可以看到實(shí)現(xiàn)Control接口的基本分為兩類,分別為葉子類和樹枝類,葉子節(jié)點(diǎn)作為最終的端點(diǎn),完成最后的操作,而樹枝類負(fù)責(zé)管理本身的所有葉子節(jié)點(diǎn)。

使用方式如下:

public static void main(String[] args) {? ? Page page=new Page();? ? Group group=new Group();? ? Item item =new Item();? ? Button button=new Button();? ? TextBox textBox=new TextBox();? ? page.add(group);? ? group.add(button);? ? group.add(item);? ? item.add(textBox);? ? page.save();}

然后我們就能看到打印出來的信息:

- Page- - Group- -? Button保存成功- - - Item- - - TextBox保存成功

可以看到,使用非常方便,并且更加便于維護(hù)。

定義:

組合模式: 組合模式(Composite Pattern)將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。組合模式使得用戶可以使用一致的方法操作單個(gè)對象和組合對象。

組合模式屬于結(jié)構(gòu)型模式

UML

組合模式如上所示,由于樹枝和葉子有著不同的操作,而葉子節(jié)點(diǎn)一般不存在添加子節(jié)點(diǎn)和刪除子節(jié)點(diǎn)操作,所有有時(shí)候?yàn)榱吮苊庹{(diào)用到葉子節(jié)點(diǎn)的這個(gè)非法操作。也可以單獨(dú)實(shí)現(xiàn)葉子節(jié)點(diǎn),這樣的模式被稱為安全模式。

應(yīng)用場景

一般應(yīng)用在哪些具有層級嵌套的結(jié)構(gòu)中,比如組織機(jī)構(gòu)樹的遍歷,比如各種控件子控件的管理等等。使用組合模式可以屏蔽用戶對層級結(jié)構(gòu)的感知。

比如MyBatis對動(dòng)態(tài)SQL的解析

比如C#中的各個(gè)控件都繼承自Controls

優(yōu)點(diǎn)

客戶端調(diào)用簡單,客戶端只需管理好根節(jié)點(diǎn)即可,不必判斷組件類型,也不用為不同的組件添加if-else

方便維護(hù),使用組合模式可以非常方便的添加擴(kuò)展層級,并且不用修改原有的代碼,符合開閉原則

缺點(diǎn)

由于屏蔽了樹枝類和葉子類的區(qū)別,因此如果某些代碼不小心調(diào)用了葉子類的非法方法,那只能在運(yùn)行時(shí)才能檢測出來。

總結(jié)

當(dāng)代碼中存在一些層級的邏輯結(jié)構(gòu),就非常的適合使用的組合模式來進(jìn)行設(shè)計(jì),這樣的設(shè)計(jì)能使得代碼非常簡單,同時(shí)組合模式又分為透明模式和安全模式,應(yīng)該按照實(shí)際情況選擇使用。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 概述 UML類圖 代碼栗子 總結(jié) 概述概念 組合模式是指將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu),組合模...
    tanoak閱讀 418評論 0 0
  • 我們知道地球和一些其他行星圍繞著太陽旋轉(zhuǎn),也知道在一個(gè)原子中,有許多電子圍繞著原子核旋轉(zhuǎn)。我曾經(jīng)想象,我們的太陽系...
    yufawu閱讀 852評論 0 4
  • 引 我們知道地球和一些其他行星圍繞著太陽旋轉(zhuǎn),也知道在一個(gè)原子中,有許多電子圍繞著原子核旋轉(zhuǎn)。我曾經(jīng)想象,我們的太...
    27億光年中的小小塵埃閱讀 153評論 0 0
  • 組合模式 組合模式,將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu),組合模式使得用戶對單個(gè)對象和組合對象的使用...
    Binaryify閱讀 538評論 0 0
  • 組合模式定義:將對象組合成樹形結(jié)構(gòu)以表示“部分整體”的層次結(jié)構(gòu)。組合模式使得用戶對單個(gè)對象和組合對象的使用具有一致...
    程序員之成長路閱讀 391評論 0 1

友情鏈接更多精彩內(nèi)容