設(shè)計模式の組合模式

組合模式

?什么是組合模式?組合模式是將一組對象組合為可像單個對象一樣被使用的結(jié)構(gòu)危队。同樣地聪建,舉個栗子來說明。

假設(shè)現(xiàn)在某國突然想教訓(xùn)一下不斷念想某魚島的某本交掏,于是開始招賢納士妆偏,招兵買馬。打戰(zhàn)吧盅弛,肯定要有士兵钱骂,士兵肯定有攻擊力,而且不同兵種攻擊力肯定不同挪鹏。假設(shè)現(xiàn)在我們有一個soldier抽象類见秽,類的定義如下:

soldier類

有兩個兵種,一個是步兵infantryman讨盒,一個是炮兵artilleryman解取,返回值的大小表示攻擊力的大小,定義如下:

有了這兩個基本兵種返顺,我們就可以開始組建軍隊(duì)了禀苦。首先,這個軍隊(duì)即可以包含自己招募來的炮兵或者步兵遂鹊,也可以包含從別的軍隊(duì)抽調(diào)過來的部隊(duì)振乏,于是分別設(shè)計了兩個對象數(shù)組來分別保存士兵對象和軍隊(duì)對象,同時也提供了添加士兵對象和軍隊(duì)對象的方法秉扑,還有移除對象的方法(沒有寫出)慧邮,軍隊(duì)總戰(zhàn)斗力就是所有作戰(zhàn)單位的攻擊力的總和,所以只需要遍歷這些作戰(zhàn)單位對象并把攻擊力數(shù)值進(jìn)行疊加即可舟陆。具體代碼如下:

由于某本是個島國误澳,我們會需要運(yùn)兵船輸送兵力,此刻可以新建一個troopCarrier類秦躯,類中可以包含特定數(shù)目的步兵或者炮兵忆谓,寫法和Army類差不多。通常我們稱army對象和troopCarrier對象為組合對象踱承,稱infantryman對象和artilleryman對象為局部對象陪毡∶啄福可以看出組合對象中需要包含添加和刪除子對象的方法,而局部對象不用毡琉,但兩者共同需要實(shí)現(xiàn)的操作是aggressivity(共同的操作集)铁瞒。

現(xiàn)在我們知道了,我們的火力輸出形式主要有單體士兵輸出和整個軍隊(duì)單位的輸出桅滋,在這里為了統(tǒng)一慧耍,我們把前文的抽象類soldier改為unit,意指作戰(zhàn)單位丐谋。

一般的組合模式會在抽象類中添加add和remove方法芍碧,所以現(xiàn)在我們的抽象基類為:

可是問題又來了,為了確保接口的統(tǒng)一号俐,組合類和局部類都繼承了這個抽象基類泌豆,但是事實(shí)上局部類并不需要實(shí)現(xiàn)這個方法,明擺著嘛吏饿,軍隊(duì)可以添加成員踪危,士兵就不可以了,除非懷孕了猪落。贞远。。笨忌。所以在不小心調(diào)用了士兵單位的Add和remove方法的時候蓝仲,應(yīng)該拋出一個異常來提示我們。這時候我們只需要在抽象基類中添加默認(rèn)實(shí)現(xiàn)就行了(具體代碼省略)官疲。

下面是改寫后的army類:

class army extends unit{

? ? ? ? ? ? ? ? private $unit=array();

? ? ? ? ? ? ? ?function addUnit(unit $unit){

? ? ? ? ? ? ? ? ? ? ? if (in_array($unit,$this->unit)) {

? ? ? ? ? ? ? ? ? ? ? ? ? ?return;

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? array_push($this->unit, $unit);

? ? ? ? ? ? ?}

? ? ? ? ? ? function removeUnit(unit $unit){

? ? ? ? ? ? ? ? ? ?$temp=array();

? ? ? ? ? ? ? ? ? foreach ($this->unit as $value) {

? ? ? ? ? ? ? ? ? if($unit !== $value){

? ? ? ? ? ? ? ? ? ? ? $temp[]=$value;

? ? ? ? ? ? ? ? ? ?}

? ? ? ? ? ? ? ?}

? ? ? ? ? ? ? ? ? $this->unit=$temp;

? ? ? ? ? ? }

? ? ? ? ? ? ? function aggressivity(){

? ? ? ? ? ? ? ? ? ? ? ? ? $res=0;

? ? ? ? ? ? ? ? ? ?foreach ($this->unit as $value) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ?$res+=$value->aggressivity();

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? return $res;

? ? ? ? ? ?}

}

如果現(xiàn)在我們又需要新的兵種如傘兵袱结,然后同時需要添加一個空降部隊(duì),需要怎么做途凫?對的垢夹,很簡單,我們只需要再新增一個傘兵局部類和空降部隊(duì)組合類即可颖榜,無需大范圍修改原來的代碼棚饵。讓我們從客戶端代碼角度來感受一下煤裙。

//某國戰(zhàn)隊(duì)

$chinese_army=new army();

//傘兵對象

$s1=new infantryman();

//炮兵對象

$s2=new artilleryman();

//傘兵對象

$s3=new paraboy();

//增加一艘運(yùn)兵船

$troopcarrier1=new troopCarrier();

$troopcarrier1->addUnit($s1);

//增加空降部隊(duì)

$air=new paratroops();

$air->addUnit($s3);

//將運(yùn)兵船和空降部隊(duì)添加到中國戰(zhàn)隊(duì)

$chinese_army->addUnit($troopcarrier1);

$chinese_army->addUnit($air);

當(dāng)我們需要得知某國戰(zhàn)隊(duì)的戰(zhàn)斗力時掩完,只需要簡單地調(diào)用$chinese_army->aggressivity()便可將復(fù)雜的操作隱藏。

看完了組合模式的代碼硼砰,也許有人有疑問了且蓬,既然局部類不需要addUnit和removeUnit方法,為什么我們還要添加呢题翰?這樣做不是顯得很冗余嗎恶阴?

為了解決這個問題诈胜,我們很自然就會想到需要對這兩種不同的對象進(jìn)行區(qū)分,組合類就應(yīng)當(dāng)實(shí)現(xiàn)addUnit和removeUnit方法冯事,而局部類就不需要去實(shí)現(xiàn)焦匈。為此,我們將這兩個操作子對象的方法降到下一級對象中昵仅,將組合類放在CompositeUnit抽象類下缓熟。

//unit抽象基類

abstract class unit{

//組合對象和局部對象的區(qū)別方法

? ? ? ? ? ?function getComposite(){

? ? ? ? ? return null;

? ? ? ? ? ?}

//共同操作集

? ? ? ? ?abstract function aggressivity();

}

//CompositeUnit抽象類,將組合類的特征抽象出來

abstract class CompositeUnit extends unit{

//作戰(zhàn)單位列表

? ? ? ? ? ? ? ? ? ? private $units=array();

? ? ? ? ? ? ? ? ? ? function getComposite(){

? ? ? ? ? ? ? ? ? ? ? ? ? ? ?return $this;

? ? ? ? ? ? ? ? ? ? }

//獲取作戰(zhàn)單位列表

? ? ? ? ? ? ? ? ? ?protected function units(){

? ? ? ? ? ? ? ? ? ? ? ? ? ? return $this->units;

? ? ? ? ? ? ? ? ? ? ?}

//添加作戰(zhàn)單位

? ? ? ? ? ? ? ? ? function addUnit(unit $unit){

? ? ? ? ? ? ? ? ? ? ? ? ? ? if (in_array($unit,$this->unit)) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return;

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? ? ?array_push($this->unit, $unit);

? ? ? ? ? ? ? ? ? ? }

//移除作戰(zhàn)單位

? ? ? ? ? ? ? ? ?function removeUnit(unit $unit){

? ? ? ? ? ? ? ? ? ? ? ? ? ? ?$temp=array();

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? foreach ($this->unit as $value) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if($unit !== $value){

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?$temp[]=$value;

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}

? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?$this->unit=$temp;

? ? ? ? ? ? ? ? }

}

組合類army:

所以摔笤,現(xiàn)在够滑,當(dāng)我們需要添加對象的時候,首先需要調(diào)用getComposite()方法判斷對象是組合對象還是局部對象吕世。

組合模式的問題:

1.當(dāng)特殊的對象越來越多彰触,組合模式開始 顯得弊大于利,因?yàn)樾枰诿總€特殊對象類中對特殊條件進(jìn)行判斷而無法自動化來強(qiáng)制執(zhí)行規(guī)則命辖,所以在大部分局部對象可互換的情況下况毅,組合模式才最適用。

2.當(dāng)對象樹中有大量的子army對象吮龄,一個簡單的調(diào)用可能會導(dǎo)致系統(tǒng)崩潰俭茧,為了降低組合操作的成本,可以在父級對象中緩沖計算結(jié)果漓帚,使接下來的調(diào)用減少系統(tǒng)開銷母债。

3.組合模式使數(shù)據(jù)保存在關(guān)系型數(shù)據(jù)庫中并不輕松,但卻非常適合持久化XML尝抖。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末毡们,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子昧辽,更是在濱河造成了極大的恐慌衙熔,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搅荞,死亡現(xiàn)場離奇詭異红氯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)咕痛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門痢甘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人茉贡,你說我怎么就攤上這事塞栅。” “怎么了腔丧?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵放椰,是天一觀的道長作烟。 經(jīng)常有香客問我,道長砾医,這世上最難降的妖魔是什么拿撩? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮如蚜,結(jié)果婚禮上绷雏,老公的妹妹穿的比我還像新娘。我一直安慰自己怖亭,他們只是感情好涎显,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著兴猩,像睡著了一般期吓。 火紅的嫁衣襯著肌膚如雪喷市。 梳的紋絲不亂的頭發(fā)上棋嘲,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天范舀,我揣著相機(jī)與錄音哮兰,去河邊找鬼。 笑死坯台,一個胖子當(dāng)著我的面吹牛躏率,可吹牛的內(nèi)容都是我干的衩侥。 我是一名探鬼主播借尿,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼刨晴,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了路翻?” 一聲冷哼從身側(cè)響起狈癞,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎茂契,沒想到半個月后蝶桶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掉冶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年真竖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厌小。...
    茶點(diǎn)故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡恢共,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出召锈,到底是詐尸還是另有隱情旁振,我是刑警寧澤获询,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布涨岁,位于F島的核電站拐袜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏梢薪。R本人自食惡果不足惜蹬铺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秉撇。 院中可真熱鬧甜攀,春花似錦、人聲如沸琐馆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瘦麸。三九已至谁撼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間滋饲,已是汗流浹背厉碟。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留屠缭,地道東北人箍鼓。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像呵曹,于是被迫代替她去往敵國和親款咖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 工廠模式類似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品奄喂,去做同樣的事情之剧,實(shí)現(xiàn)同樣的效果;這時候需要使用工廠模式。簡單...
    舟漁行舟閱讀 7,758評論 2 17
  • 單例模式 適用場景:可能會在場景中使用到對象砍聊,但只有一個實(shí)例背稼,加載時并不主動創(chuàng)建,需要時才創(chuàng)建 最常見的單例模式玻蝌,...
    Obeing閱讀 2,067評論 1 10
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理蟹肘,服務(wù)發(fā)現(xiàn),斷路器俯树,智...
    卡卡羅2017閱讀 134,656評論 18 139
  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 10,967評論 6 13
  • 2016.02.17 22:00-23:07 一帘腹、本次分享的大綱如下: 1.兩個維度認(rèn)識Tom老師高大上和真實(shí)版 ...
    Tom教練閱讀 969評論 5 3