嬰幼兒網(wǎng)站模板鎮(zhèn)江百度推廣公司
什么是組合模式
又名部分整體模式,是用于把一組相似的對(duì)象當(dāng)作一個(gè)單一的對(duì)象。組合模式依據(jù)樹形結(jié)構(gòu)來組合對(duì)象,用來表示部分以及整體層次。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它創(chuàng)建了對(duì)象組的樹形結(jié)構(gòu)。
結(jié)構(gòu)
- 抽象根節(jié)點(diǎn)(Component):定義系統(tǒng)各層次對(duì)象的共有方法和屬性,可以預(yù)先定義一些默認(rèn)行為和屬性。
- 樹枝節(jié)點(diǎn)(Composite):定義樹枝節(jié)點(diǎn)的行為,存儲(chǔ)子節(jié)點(diǎn),組合樹枝節(jié)點(diǎn)和葉子節(jié)點(diǎn)形成一個(gè)樹形結(jié)構(gòu)。
- 葉子節(jié)點(diǎn)(Leaf):葉子節(jié)點(diǎn)對(duì)象,其下再無(wú)分支,是系統(tǒng)層次遍歷的最小單位。
UML類圖
代碼理解
package com.babs.pattern.comprise;/*** 菜單組件 抽象根節(jié)點(diǎn)** @author TYT* @version 1.0.0*/
public abstract class MenuComponent {// 菜單組件的名稱protected String name;// 菜單組件的層級(jí)protected int level;// 添加子菜單public void add(MenuComponent menuComponent) {throw new UnsupportedOperationException();}// 移除子菜單public void remove(MenuComponent menuComponent) {throw new UnsupportedOperationException();}// 獲取指定的子菜單public MenuComponent getChild(int index) {throw new UnsupportedOperationException();}// 獲取菜單名稱或菜單項(xiàng)名稱public String getName() {return name;}// 打印菜單名稱的方法(包含子菜單和子菜單項(xiàng))public abstract void print();
}package com.babs.pattern.comprise;import java.util.ArrayList;
import java.util.List;/*** 菜單類 樹枝節(jié)點(diǎn)** @author TYT* @version 1.0.0*/
public class Menu extends MenuComponent {// 菜單可以有多個(gè)子菜單或者子菜單項(xiàng)private List<MenuComponent> menuComponentList = new ArrayList<MenuComponent>();public Menu(String name, int level) {this.name = name;this.level = level;}@Overridepublic void add(MenuComponent menuComponent) {menuComponentList.add(menuComponent);}@Overridepublic void remove(MenuComponent menuComponent) {menuComponentList.remove(menuComponent);}@Overridepublic MenuComponent getChild(int index) {return menuComponentList.get(index);}@Overridepublic void print() {for (int i = 0; i < level; i++) {System.out.print("--");}// 打印菜單名稱System.out.println(name);// 打印子菜單名稱和子菜單名稱menuComponentList.forEach(MenuComponent::print);}
}package com.babs.pattern.comprise;/*** 菜單項(xiàng) 葉子節(jié)點(diǎn)** @author TYT* @version 1.0.0*/
public class MenuItem extends MenuComponent {public MenuItem(String name, int level) {this.name = name;this.level = level;}@Overridepublic void print() {for (int i = 0; i < level; i++) {System.out.print("--");}// 打印菜單項(xiàng)的名稱System.out.println(name);}
}package com.babs.pattern.comprise;/*** 客戶端測(cè)試** @author TYT* @version 1.0.0*/
public class Client {public static void main(String[] args) {MenuComponent menu1 = new Menu("菜單管理", 2);menu1.add(new MenuItem("menu1子菜單1", 3));menu1.add(new MenuItem("menu1子菜單2", 3));menu1.add(new MenuItem("menu1子菜單3", 3));MenuComponent menu2 = new Menu("權(quán)限管理", 2);menu2.add(new MenuItem("menu2子菜單1", 3));menu2.add(new MenuItem("menu2子菜單2", 3));menu2.add(new MenuItem("menu2子菜單3", 3));MenuComponent menu3 = new Menu("角色管理", 2);menu3.add(new MenuItem("menu3子菜單1", 3));menu3.add(new MenuItem("menu3子菜單2", 3));menu3.add(new MenuItem("menu3子菜單3", 3));MenuComponent component = new Menu("系統(tǒng)管理", 1);component.add(menu1);component.add(menu2);component.add(menu3);component.print();}
}
組合模式的分類
在使用組合模式時(shí),根據(jù)抽象構(gòu)件類的定義形式,我們可將組合模式分為透明組合模式和安全組合模式兩種形式。
- 透明組合模式
透明組合模式中,抽象根節(jié)點(diǎn)角色中聲明了所有用于管理成員對(duì)象的方法,比如在示例中 MenuComponent
聲明了 add
、remove
、getChild
方法,這樣做的好處是確保所有的構(gòu)件類都有相同的接口。透明組合模式也是組合模式的標(biāo)準(zhǔn)形式。透明組合模式的缺點(diǎn)是不夠安全,因?yàn)槿~子對(duì)象和容器對(duì)象在本質(zhì)上是有區(qū)別的,葉子對(duì)象不可能有下一個(gè)層次的對(duì)象,即不可能包含成員對(duì)象,因此為其提供 add()、remove() 等方法是沒有意義的,這在編譯階段不會(huì)出錯(cuò),但在運(yùn)行階段如果調(diào)用這些方法可能會(huì)出錯(cuò)(如果沒有提供相應(yīng)的錯(cuò)誤處理代碼)
- 安全組合模式
在安全組合模式中,在抽象構(gòu)件角色中沒有聲明任何用于管理成員對(duì)象的方法,而是在樹枝節(jié)點(diǎn) Menu
類中聲明并實(shí)現(xiàn)這些方法。安全組合模式的缺點(diǎn)是不夠透明,因?yàn)槿~子構(gòu)件和容器構(gòu)件具有不同的方法,且容器構(gòu)件中那些用于管理成員對(duì)象的方法沒有在抽象構(gòu)件類中定義,因此客戶端不能完全針對(duì)抽象編程,必須有區(qū)別地對(duì)待葉子構(gòu)件和容器構(gòu)件。
優(yōu)點(diǎn)
- 一致性:客戶可以一致地對(duì)待個(gè)體對(duì)象和對(duì)象組合。
- 靈活性:可以很容易地增加新的組合類型,符合開閉原則。
- 簡(jiǎn)化高層代碼:因?yàn)榻M合模式隱藏了對(duì)象之間的關(guān)系,所以高層代碼不需要關(guān)心是單個(gè)對(duì)象還是組合對(duì)象。
缺點(diǎn)
- 可能會(huì)導(dǎo)致設(shè)計(jì)復(fù)雜化:如果系統(tǒng)中存在大量不同類型的組件,那么維護(hù)這個(gè)模式可能會(huì)變得相當(dāng)復(fù)雜。
- 不容易限制容器中的構(gòu)件:不容易用繼承的方法來增加構(gòu)件的新功能
使用場(chǎng)景
- 當(dāng)程序結(jié)構(gòu)有類似樹一樣的層級(jí)關(guān)系時(shí),例如文件系統(tǒng)、視圖樹、公司組織架構(gòu)等。
- 當(dāng)需要以統(tǒng)一的方式操作單個(gè)對(duì)象和由這些對(duì)象組成的組合對(duì)象時(shí)。