一、介紹续搀,定義
將對(duì)象組合呈樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)蛀缝,使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。
比如目代,總公司下設(shè)總公司行政部、總公司研發(fā)部和子公司嗤练,而子公司又下設(shè)子公司行政部和子公司研發(fā)部榛了。
二、使用場(chǎng)景
(1)表示對(duì)象的部分-整體層次結(jié)構(gòu)時(shí)煞抬;
(2)從一個(gè)整體中能夠獨(dú)立出部分模塊或功能的場(chǎng)景霜大。
三、UML類圖
角色說明:
Component(抽象組件角色):定義參加組合對(duì)象的共有方法和屬性革答,可以定義一些默認(rèn)的函數(shù)或?qū)傩浴?br>
Leaf(葉子節(jié)點(diǎn)):葉子沒有子節(jié)點(diǎn)战坤,因此是組合樹的最小構(gòu)建單元曙强。
Composite(樹枝節(jié)點(diǎn)):定義所有枝干節(jié)點(diǎn)的行為,存儲(chǔ)子節(jié)點(diǎn)途茫,實(shí)現(xiàn)相關(guān)操作碟嘴。
四、通用代碼
1囊卜、安全的組合模式
抽象根節(jié)點(diǎn):為組合中的對(duì)象聲明接口
public abstract class Component {
// 節(jié)點(diǎn)名
protected String name;
public Component(String name) {
this.name = name;
}
/ /具體的邏輯方法由子類實(shí)現(xiàn)
public abstract void doSomething();
}
具體枝干節(jié)點(diǎn):定義有子節(jié)點(diǎn)的那些枝干節(jié)點(diǎn)的行為娜扇,存儲(chǔ)子節(jié)點(diǎn)
public class Composite extends Component {
//存儲(chǔ)節(jié)點(diǎn)的容器
private List<Component> components = new ArrayList<>();
public Composite(String name) {
super(name);
}
@Override
public void doSomething() {
System.out.println(name);
if (components != null) {
for (Component component : components) {
component.doSomething();
}
}
}
/**
* 添加子節(jié)點(diǎn)
* @param child 子節(jié)點(diǎn)
*/
public void addChild(Component child) {
components.add(child);
}
/**
* 移除子節(jié)點(diǎn)
* @param child 子節(jié)點(diǎn)
*/
public void removeChild(Component child) {
components.remove(child);
}
/**
* 獲取子節(jié)點(diǎn)
* @param index子節(jié)點(diǎn)對(duì)應(yīng)下標(biāo)
* @return 子節(jié)點(diǎn)
*/
public Component getChildren(int index) {
return components.get(index);
}
}
具體葉子節(jié)點(diǎn):葉子節(jié)點(diǎn)沒有子節(jié)點(diǎn),在組合中定義節(jié)點(diǎn)對(duì)象的行為
public class Leaf extends Component{
public Leaf(String name) {
super(name);
}
@Override
public void doSomething() {
System.out.println(name);
}
}
客戶類:通過Component接口操縱組合節(jié)點(diǎn)的對(duì)象
public class Client {
public static void main(String[] args) {
// 構(gòu)造一個(gè)根節(jié)點(diǎn)
Composite root = new Composite("Root");
// 構(gòu)造兩個(gè)枝干節(jié)點(diǎn)
Composite branch1 = new Composite("Branch1");
Composite branch2 = new Composite("Branch2");
// 構(gòu)造兩個(gè)葉子節(jié)點(diǎn)
Leaf leaf1 = new Leaf("Leaf1");
Leaf leaf2 = new Leaf("Leaf2");
// 將葉子節(jié)點(diǎn)添加至枝干節(jié)點(diǎn)中
branch1.addChild(leaf1);
branch2.addChild(leaf2);
// 將枝干節(jié)點(diǎn)添加至根節(jié)點(diǎn)中
root.addChild(branch1);
root.addChild(branch2);
// 執(zhí)行方法
root.doSomething();
}
}
結(jié)果:
這里有一個(gè)很大的弊端栅组,我們?cè)诳蛻纛愔兄苯邮褂昧薈omponent的實(shí)現(xiàn)類雀瓢,這與依賴倒置原則(高層次的模塊不依賴于低層次的模塊的實(shí)現(xiàn)細(xì)節(jié)的目的)相違背。
我們將位于Composite的一些方法定義到Component中
2透明的組合模式抽象根節(jié)點(diǎn):為組合中的對(duì)象聲明接口
public abstract class Component {
// 節(jié)點(diǎn)名
protected String name;
public Component(String name) {
this.name = name;
}
/**
* 具體的邏輯方法由子類實(shí)現(xiàn)
*/
public abstract void doSomething();
/**
* 添加子節(jié)點(diǎn)
* @param child子節(jié)點(diǎn)
*/
public abstract void addChild(Component child);
/**
* 移除子節(jié)點(diǎn)
* @param child子節(jié)點(diǎn)
*/
public abstract void removeChild(Component child);
/**
* 獲取子節(jié)點(diǎn)
* @param index子節(jié)點(diǎn)對(duì)應(yīng)下標(biāo)
* @return 子節(jié)點(diǎn)
*/
public abstract Component getChildren(int index);
}
透明的組合模式具體枝干節(jié)點(diǎn):定義有子節(jié)點(diǎn)的那些枝干節(jié)點(diǎn)的行為玉掸,存儲(chǔ)子節(jié)點(diǎn)
public class Composite extends Component {
/*
* 存儲(chǔ)節(jié)點(diǎn)的容器
*/
private List<Component> components = new ArrayList<>();
public Composite(String name) {
super(name);
}
@Override
public void doSomething() {
System.out.println(name);
if (components != null) {
for (Component component : components) {
component.doSomething();
}
}
}
@Override
public void addChild(Component child) {
components.add(child);
}
@Override
public void removeChild(Component child) {
components.remove(child);
}
@Override
public Component getChildren(int index) {
return components.get(index);
}
}
透明的組合模式具體葉子節(jié)點(diǎn):葉子節(jié)點(diǎn)沒有子節(jié)點(diǎn)刃麸,在組合中定義節(jié)點(diǎn)對(duì)象的行為
public class Leaf extends Component {
public Leaf(String name) {
super(name);
}
@Override
public void doSomething() {
System.out.println(name);
}
@Override
public void addChild(Component child) {
throw new UnsupportedOperationException("葉子節(jié)點(diǎn)沒有子節(jié)點(diǎn)");
}
@Override
public void removeChild(Component child) {
throw new UnsupportedOperationException("葉子節(jié)點(diǎn)沒有子節(jié)點(diǎn)");
}
@Override
public Component getChildren(int index) {
throw new UnsupportedOperationException("葉子節(jié)點(diǎn)沒有子節(jié)點(diǎn)");
}
}
透明的組合模式客戶類:通過Component接口操縱組合節(jié)點(diǎn)的對(duì)象
public class Client {
public static void main(String[] args) {
// 構(gòu)造一個(gè)根節(jié)點(diǎn)
Component root = new Composite("Root");
// 構(gòu)造兩個(gè)枝干節(jié)點(diǎn)
Component branch1 = new Composite("Branch1");
Component branch2 = new Composite("Branch2");
// 構(gòu)造兩個(gè)葉子節(jié)點(diǎn)
Component leaf1 = new Leaf("Leaf1");
Component leaf2 = new Leaf("Leaf2");
// 將葉子節(jié)點(diǎn)添加至枝干節(jié)點(diǎn)中
branch1.addChild(leaf1);
branch2.addChild(leaf2);
// 將枝干節(jié)點(diǎn)添加至根節(jié)點(diǎn)中
root.addChild(branch1);
root.addChild(branch2);
// 執(zhí)行方法
root.doSomething();
}
}
五、簡(jiǎn)單實(shí)現(xiàn)
文件和文件夾
六司浪、模式的優(yōu)缺點(diǎn):
組合模式在Android中最經(jīng)典的實(shí)現(xiàn)就是View和ViewGrounp的嵌套組合泊业。當(dāng)然這種模式真正需要開發(fā)者去實(shí)現(xiàn)的并不多。
優(yōu)點(diǎn):
(1)可以清楚的定義分層次的復(fù)雜對(duì)象断傲,表示對(duì)象的全部或部分層次脱吱,它讓高層模塊忽略了層次的差異,方便對(duì)整個(gè)層次結(jié)構(gòu)進(jìn)行控制认罩;
(2)高層模塊可以一致的使用一個(gè)組合結(jié)構(gòu)或其中單個(gè)對(duì)象箱蝠,不必關(guān)心處理的是單個(gè)對(duì)象還是整個(gè)組合結(jié)構(gòu),簡(jiǎn)化了高層模塊的代碼垦垂;
(3)在組合模式中增加新的枝干構(gòu)件和葉子構(gòu)件都很方便宦搬,無須對(duì)現(xiàn)有類庫(kù)進(jìn)行任何修改,符合“開閉原則”劫拗;
(4)組合模式為樹形結(jié)構(gòu)的面向?qū)ο髮?shí)現(xiàn)提供了一種靈活的解決方案间校,通過葉子對(duì)象和枝干對(duì)象的遞歸組合,可以形成復(fù)雜的樹形結(jié)構(gòu)页慷,但對(duì)樹形結(jié)構(gòu)的控制卻非常簡(jiǎn)單憔足。
缺點(diǎn):
在新增構(gòu)件時(shí)不好對(duì)枝干中的構(gòu)件類型進(jìn)行限制,不能依賴類型系統(tǒng)來施加這些約束酒繁,因?yàn)樵诖蠖鄶?shù)情況下滓彰,它們都來自于相同的抽象層,此時(shí)州袒,必須及時(shí)進(jìn)行類型檢查來實(shí)現(xiàn)揭绑,這個(gè)實(shí)現(xiàn)過程較為復(fù)雜。