組合模式,英文為COMPOSITE模式,屬于對象結構型模式。用于組合多個對象形成樹形結構以表示具有“整體—部分”關系的層次結構。組合模式對單個對象(即葉子對象)群組合對象(即容器對象)的使用具有一緻性。通常樹形結構,比如公司組織結構,檔案目錄,系統菜單,xml檔案解析等都可以采用組合模式實作。
一、适用場景
1、在具有整體和部分的層次結構中,希望通過一種方式忽略整體與部分的差異,用戶端可以一緻地對待它們。
2、 在一個使用面向對象語言開發的系統中需要處理一個樹形結構。
3、在一個系統中能夠分離出葉子對象和容器對象,而且它們的類型不固定,需要增加一些新的類型。
二、UML圖
組合模式的關鍵是定義了一個抽象構件類,它既可以代表葉子,又可以代表容器,而用戶端針對該抽象構件類進行程式設計,無須知道它到底表示的是葉子還是容器,可以對其進行統一處理。同時容器對象與抽象構件類之間還建立一個聚合關聯關系,在容器對象中既可以包含葉子,也可以包含容器,以此實作遞歸組合,形成一個樹形結構。
三、Java實作
package study.patterns.composite;
import java.util.ArrayList;
import java.util.List;
/**
* 組合模式:組合多個對象形成樹形結構以表示具有“整體—部分”關系的層次結構。
* 組合模式對單個對象(即葉子對象)群組合對象(即容器對象)的使用具有一緻性。
* @author qbg
*/
public class CompositePattern {
public static void main(String[] args) {
IMessage forum = new Forum("灌水區", "admin");
IMessage m1 = new PostMessage("張三", "大象進醫院了!!!");
IMessage m2 = new PostMessage("李四", "怎麼可能?");
IMessage m3 = new PostMessage("張三", "怎麼不可能?!大象踩着螞蟻,然後骨折了!!!");
m1.add(m2);
m2.add(m3);
forum.add(m1);
forum.print();
}
}
/**
* 論壇版塊,文章抽象接口。
*/
interface IMessage{
public void add(IMessage message);
public void delete(int i);
public IMessage getChild(int i);
public void print();
}
/**
* 論壇文章:原始帖或回帖
*/
class PostMessage implements IMessage{
private String content; //内容
private String author; //發帖人
private List<IMessage> messages = new ArrayList<IMessage>();//回帖
public PostMessage(String author,String content){
this.author = author;
this.content = content;
}
@Override
public void add(IMessage message) {
messages.add(message);
}
@Override
public void delete(int i) {
if(i>messages.size()){
throw new IllegalArgumentException("索引越界...");
}
messages.remove(i);
}
@Override
public IMessage getChild(int i) {
return messages.get(i);
}
@Override
public void print() {
System.out.println(author+"說:"+content);
//遞歸調用成員構件的業務方法實作
for(IMessage message : messages){
message.print();
}
}
}
/**
* 論壇版塊:由相應文章組成
*/
class Forum implements IMessage{
private String name; //版塊名
private String admin;//版主
private List<IMessage> messages = new ArrayList<IMessage>();//文章
public Forum(String name,String admin){
this.name = name;
this.admin = admin;
}
@Override
public void add(IMessage message) {
messages.add(message);
}
@Override
public void delete(int i) {
if(i>messages.size()){
throw new IllegalArgumentException("索引越界...");
}
messages.remove(i);
}
@Override
public IMessage getChild(int i) {
return messages.get(i);
}
@Override
public void print() {
System.out.println("版塊:"+name+",管理者:"+admin);
System.out.println("文章内容:");
//遞歸調用成員構件的業務方法實作
for(IMessage message : messages){
message.print();
}
}
}
運作結果:
版塊:灌水區,管理者:admin
文章内容:
張三說:大象進醫院了!!!
李四說:怎麼可能?
張三說:怎麼不可能?!大象踩着螞蟻,然後骨折了!!!
四、模式優缺點
優點:
1、組合模式可以清楚地定義分層次的複雜對象,表示對象的全部或部分層次,它讓用戶端忽略了層次的差異,友善對整個層次結構進行控制。
2、用戶端可以一緻地使用一個組合結構或其中單個對象,不必關心處理的是單個對象還是整個組合結構,簡化了用戶端代碼。
3、在組合模式中增加新的容器構件和葉子構件都很友善,無須對現有類庫進行任何修改,符合“開閉原則”。
4、組合模式為樹形結構的面向對象實作提供了一種靈活的解決方案,通過葉子對象和容器對象的遞歸組合,可以形成複雜的樹形結構,但對樹形結構的控制卻非常簡單。
缺點:
1、 在增加新構件時很難對容器中的構件類型進行限制。有時候我們希望一個容器中隻能有某些特定類型的對象,例如在某個檔案夾中隻能包含文本檔案,使用組合模式時,不能依賴類型系統來施加這些限制,因為它們都來自于相同的抽象層,在這種情況下,必須通過在運作時進行類型檢查來實作,這個實作過程較為複雜。