Java設(shè)計模式之組合模式(Composite模式)介紹
Composite定義:將對象以樹形結(jié)構(gòu)組織起來,以達成“部分-整體” 的層次結(jié)構(gòu),使得客戶端對單個對象和組合對象的使用具有一致性。
Composite比較容易理解,想到Composite就應(yīng)該想到樹形結(jié)構(gòu)圖。組合體內(nèi)這些對象都有共同接口,當組合體一個對象的方法被調(diào)用執(zhí)行時,Composite將遍歷(Iterator)整個樹形結(jié)構(gòu),尋找同樣包含這個方法的對象并實現(xiàn)調(diào)用執(zhí)行。可以用牽一動百來形容。
所以Composite模式使用到Iterator模式,和Chain of Responsibility模式類似。
Composite好處:
1.使客戶端調(diào)用簡單,客戶端可以一致的使用組合結(jié)構(gòu)或其中單個對象,用戶就不必關(guān)系自己處理的是單個對象還是整個組合結(jié)構(gòu),這就簡化了客戶端代碼。
2.更容易在組合體內(nèi)加入對象部件??蛻舳瞬槐匾驗榧尤肓诵碌膶ο蟛考拇a。
如何使用Composite
首先定義一個接口或抽象類,這是設(shè)計模式通用方式了,其他設(shè)計模式對接口內(nèi)部定義限制不多,Composite卻有個規(guī)定,那就是要在接口內(nèi)部定義一個用于訪問和管理Composite組合體的對象們(或稱部件Component)。
下面的代碼是以抽象類定義,一般盡量用接口interface。
public abstract class Equipment{
private String name;
//網(wǎng)絡(luò)價格
public abstract double netPrice();
//折扣價格
public abstract double discountPrice();
//增加部件方法
public boolean add(Equipment equipment) { return false; }
//刪除部件方法
public boolean remove(Equipment equipment) { return false; }
//注意這里,這里就提供一種用于訪問組合體類的部件方法。
public Iterator iter() { return null; }
public Equipment(final String name) { this.name=name; }
}
抽象類Equipment就是Component定義,代表著組合體類的對象們,Equipment中定義幾個共同的方法。
public class Disk extends Equipment{
public Disk(String name) { super(name); }
//定義Disk網(wǎng)絡(luò)價格為1
public double netPrice() { return 1.; }
//定義了disk折扣價格是0.5 對折。
public double discountPrice() { return .5; }
}
Disk是組合體內(nèi)的一個對象,或稱一個部件,這個部件是個單獨元素( Primitive)。
還有一種可能是,一個部件也是一個組合體,就是說這個部件下面還有'兒子',這是樹形結(jié)構(gòu)中通常的情況,應(yīng)該比較容易理解?,F(xiàn)在我們先要定義這個組合體:
abstract class CompositeEquipment extends Equipment{
private int i=0;
//定義一個Vector 用來存放'兒子'
private Lsit equipment=new ArrayList();
public CompositeEquipment(String name) { super(name); }
public boolean add(Equipment equipment) {
this.equipment.add(equipment);
return true;
}
public double netPrice(){
double netPrice=0.;
Iterator iter=equipment.iterator();
for(iter.hasNext())
netPrice+=((Equipment)iter.next()).netPrice();
return netPrice;
}
public double discountPrice(){
double discountPrice=0.;
Iterator iter=equipment.iterator();
for(iter.hasNext())
discountPrice+=((Equipment)iter.next()).discountPrice();
return discountPrice;
}
//注意這里,這里就提供用于訪問自己組合體內(nèi)的部件方法。
//上面dIsk 之所以沒有,是因為Disk是個單獨(Primitive)的元素.
public Iterator iter(){
return equipment.iterator() ;
}
//重載Iterator方法
public boolean hasNext() { return i<equipment.size(); }
//重載Iterator方法
public Object next(){
if(hasNext())
return equipment.elementAt(i++);
else
throw new NoSuchElementException();
}
}
上面CompositeEquipment繼承了Equipment,同時為自己里面的對象們提供了外部訪問的方法,重載了Iterator,Iterator是Java的Collection的一個接口,是Iterator模式的實現(xiàn)。
我們再看看CompositeEquipment的兩個具體類:盤盒Chassis和箱子Cabinet,箱子里面可以放很多東西,如底板,電源盒,硬盤盒等;盤盒里面可以放一些小設(shè)備,如硬盤 軟驅(qū)等。無疑這兩個都是屬于組合體性質(zhì)的。
public class Chassis extends CompositeEquipment{
public Chassis(String name) { super(name); }
public double netPrice() { return 1.+super.netPrice(); }
public double discountPrice() { return .5+super.discountPrice(); }
}
public class Cabinet extends CompositeEquipment{
public Cabinet(String name) { super(name); }
public double netPrice() { return 1.+super.netPrice(); }
public double discountPrice() { return .5+super.discountPrice(); }
}
至此我們完成了整個Composite模式的架構(gòu)。
我們可以看看客戶端調(diào)用Composote代碼:
Cabinet cabinet=new Cabinet("Tower");
Chassis chassis=new Chassis("PC Chassis");
//將PC Chassis裝到Tower中 (將盤盒裝到箱子里)
cabinet.add(chassis);
//將一個10GB的硬盤裝到 PC Chassis (將硬盤裝到盤盒里)
chassis.add(new Disk("10 GB"));
//調(diào)用 netPrice()方法;
System.out.println("netPrice="+cabinet.netPrice());
System.out.println("discountPrice="+cabinet.discountPrice());
上面調(diào)用的方法netPrice()或discountPrice(),實際上Composite使用Iterator遍歷了整個樹形結(jié)構(gòu),尋找同樣包含這個方法的對象并實現(xiàn)調(diào)用執(zhí)行。
Composite是個很巧妙體現(xiàn)智慧的模式,在實際應(yīng)用中,如果碰到樹形結(jié)構(gòu),我們就可以嘗試是否可以使用這個模式。
以論壇為例,一個版(forum)中有很多帖子(message),這些帖子有原始貼,有對原始貼的回應(yīng)貼,是個典型的樹形結(jié)構(gòu),那么當然可以使用Composite模式,那么我們進入Jive中看看,是如何實現(xiàn)的.
Jive解剖
在Jive中 ForumThread是ForumMessages的容器container(組合體)。也就是說,F(xiàn)orumThread類似我們上例中的 CompositeEquipment.它和messages的關(guān)系如下所示:
[thread]
|- [message]
|- [message]
|- [message]
|- [message]
|- [message]
我們在ForumThread看到如下代碼:
public interface ForumThread {
....
public void addMessage(ForumMessage parentMessage, ForumMessage newMessage)
throws UnauthorizedException;
public void deleteMessage(ForumMessage message)
throws UnauthorizedException;
public Iterator messages();
....
}
類似CompositeEquipment,提供用于訪問自己組合體內(nèi)的部件方法:增加、刪除、遍歷。
結(jié)合我的其他模式中對Jive的分析,我們已經(jīng)基本大體理解了Jive論壇體系的框架,如果你之前不理解設(shè)計模式,而直接去看Jive源代碼,你肯定無法看懂。
相關(guān)文章
AndroidHttpClient使用Cookie應(yīng)用分析
今天想把一個用使用了HttpClient的自動簽到小程序移植到Android上,還好Android的SDK自帶了HttpClient的包.當然也可以繼續(xù)使用DefaultHttpClient,但用為Android定制的AndroidHttpClient自然更好2012-11-11Mybatis入門教程(四)之mybatis動態(tài)sql
這篇文章主要介紹了Mybatis入門教程(四)之mybatis動態(tài)sql的相關(guān)資料,涉及到動態(tài)sql及動態(tài)sql的作用知識,本文介紹的非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-09-09淺談SpringBoot 中關(guān)于自定義異常處理的套路
這篇文章主要介紹了淺談SpringBoot 中關(guān)于自定義異常處理的套路,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04Java泛型T,E,K,V,N,?與Object區(qū)別和含義
Java?泛型(generics)是?JDK?5?中引入的一個新特性,?泛型提供了編譯時類型安全檢測機制,該機制允許程序員在編譯時檢測到非法的類型。本文將詳細講講Java泛型T、E、K、V、N、?和Object區(qū)別和含義,需要發(fā)可以參考一下2022-03-03Java求兩個正整數(shù)的最大公約數(shù)和最小公倍數(shù)
這篇文章主要介紹了輸入兩個正整數(shù)m和n,求其最大公約數(shù)和最小公倍數(shù),需要的朋友可以參考下2017-02-02