組合模式
摘要
本文通過簡潔的模式描述,應用場景的詳細代碼實現,以及匹配的UML,詳解介紹了組合模式的原理及應用。本文可幫助讀者快速掌握組合模式,以便工作學習中使用組合模式。
一、組合模式
在我們的生活中,很多事物都有一個組織架構的分層現象。比如一個國家的組織結構:國家–省份–市--縣–鎮--村–人,其中除國家是唯一對象之外,其它部分都是多個對象實體;再比如一個集團的組織架構:集團–一級公司–二級公司–部門–小組–程序員,同樣,除集團是唯一對象之外,其它部分都可以是多個實體。這兩個例子中還有一個共同的特點,他們的組織架構中最後一個對象都是不可再分的,不會再有子組織結構。
在組織結構中,如果上層有消息需要通知到最底層時,每一層的任務都是將消息通知到下一層,比如集團級只與一級公司交互,再由一級公司與二級公司交互,由此類推,一直到小組與程序員交互,在這個交互的過程中,集團並沒有與程序員直接交互,所以實現了集團與程序員之間的解耦操作,方便了其內部組織結構的變動,如程序員還了一批人,從組織架構、公司運行上來說並沒有什麼影響。同樣,單個部門換掉,也不會導致該組織架構的大量改動,保證了“開閉原則”,也體現了“職責單一原則”,只是部門級以下的成員會受到影響,他們將不再接收到上級的消息,或將他們轉入 其它部門。
在程序的世界裏,有一種熟悉的數據結構——樹,樹結構就類似於上面組織結構。根節點只有一個,可以有多個子節點,也可以多個葉節點,但葉節點不能有子節點或子葉節點。組合模式將各個對象的之間的組織結構封裝起來,一是爲了保證組織架構不會被破壞,二是爲了方便第三方的使用,第三方不用清楚組織架構是怎樣,他只需要對某個節點進行操作。
二、組合模式的實現
2.1 場景設計
對於組合模式,暫沒有想到身邊的具體實例,所以本文就以節點和葉節點的命名方式來實現組合模式。從上面的解析中可知:根節點只有一個,可以有多個子節點,也可以多個葉節點,但葉節點不能有子節點或子葉節點。所以節點可以看成是一個容器。在消息的傳送中,節點和葉節點都能收到消息,所以他們又具有相同的功能,所以節點和葉節點可以共同繼承與一個共同的藉口或抽象類。
2.2 代碼實現
2.2.1 Component 抽象
package ft.patterns.composite;
import java.util.ArrayList;
import java.util.List;
public abstract class Component {
public Component() {
this.leafList = new ArrayList<Component>();
}
List<Component> leafList;
void add(Component leaf){
throw new UnsupportedOperationException();
};
boolean remove(Component leaf) {
throw new UnsupportedOperationException();
};
void execute() {
throw new UnsupportedOperationException();
}
}
2.2.2 Composite 節點類
package ft.patterns.composite;
import java.util.ArrayList;
import java.util.List;
public class Composite extends Component{
private String name;
private List<Component> componentList;
public Composite(String name) {
super();
this.name = name;
componentList = new ArrayList<Component>();
}
@Override
void add(Component leaf) {
if(leaf != null)
componentList.add(leaf);
}
@Override
boolean remove(Component leaf) {
int result = componentList.indexOf(leaf);
if(result != -1) {
componentList.remove(result);
return true;
}
return false;
}
@Override
void execute() {
System.out.println("hello "+name);
for(Component temp : componentList) {
temp.execute();
}
}
}
2.2.3 Leaf 葉節點類
package ft.patterns.composite;
public class Leaf extends Component{
private String name;
public Leaf(String name){
super();
this.name = name;
}
@Override
void execute() {
System.out.println("hello " + name);
}
}
2.2.4 Main 測試類
package ft.patterns.composite;
public class Main {
public static void main(String[] args) {
Component root = new Composite("root");
Component leaf1 = new Leaf("leaf1");
Component leaf2 = new Leaf("leaf2");
Component component1 = new Composite("component1");
Component leaf3 = new Leaf("leaf3");
Component leaf4 = new Leaf("leaf4");
Component leaf5 = new Leaf("leaf5");
Component component2 = new Composite("component2");
Component leaf6 = new Leaf("leaf6");
Component component3 = new Composite("component3");
component3.add(leaf3);
component3.add(leaf4);
component1.add(leaf2);
component1.add(component3);
component2.add(leaf5);
component2.add(leaf6);
root.add(component1);
root.add(component2);
root.add(leaf1);
System.out.println("########################");
root.execute();
System.out.println("########################");
component1.execute();
System.out.println("########################");
component3.execute();
System.out.println("########################");
component2.execute();
}
}
2.2.5 測試結果
########################
hello root
hello component1
hello leaf2
hello component3
hello leaf3
hello leaf4
hello component2
hello leaf5
hello leaf6
hello leaf1
########################
hello component1
hello leaf2
hello component3
hello leaf3
hello leaf4
########################
hello component3
hello leaf3
hello leaf4
########################
hello component2
hello leaf5
hello leaf6