設(shè)計(jì)模式——組合模式

將對(duì)象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu),使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性处面,以便能夠讓客戶端以一致的方式處理個(gè)別對(duì)象以及組合對(duì)象。

組合模式也稱為部分整體模式,通過抽象出部分與整體的公共部分接口切厘,然后達(dá)到部分與整體在被操作使用上的一致性珊皿,用戶忽略組合對(duì)象與單個(gè)對(duì)象的不同网缝,統(tǒng)一地使用組合結(jié)構(gòu)中的所有對(duì)象。

看下組合模式的組成

  1. 抽象構(gòu)件角色Component:它為組合中的對(duì)象聲明接口蟋定,定義參加組合對(duì)象的共有方法和屬性粉臊,可以定義一些默認(rèn)的函數(shù)或?qū)傩浴?/li>
  2. 樹葉構(gòu)件角色Leaf:在組合中表示葉子節(jié)點(diǎn),實(shí)現(xiàn)抽象構(gòu)件角色聲明的接口驶兜。
  3. 樹枝構(gòu)件角色Composite:在組合中表示分支節(jié)點(diǎn)對(duì)象——有子節(jié)點(diǎn)扼仲,實(shí)現(xiàn)抽象構(gòu)件角色聲明的接口.它的作用是組合樹枝節(jié)點(diǎn)和葉子節(jié)點(diǎn)形成一個(gè)樹形結(jié)構(gòu)。

安全性組合與透明性組合
組合模式中必須提供樹枝節(jié)點(diǎn)對(duì)子對(duì)象的管理方法促王,不然無法完成對(duì)子對(duì)象的添加刪除等等操作犀盟,也就失去了靈活性和擴(kuò)展性。這里就涉及到這些方法是定義在Compnent中還是定義在Compsite中蝇狼?

一種方式是在Component里面聲明所有的用來管理子類對(duì)象的方法阅畴,以達(dá)到Component接口的最大化(如下圖所示)。目的就是為了使客戶看來在接口層次上樹葉和分支沒有區(qū)別——透明性迅耘。但樹葉是不存在子類的贱枣,因此Component聲明的一些方法對(duì)于樹葉來說是不適用的。這樣也就帶來了一些安全性問題颤专。


透明性UML.jpg

另一種方式就是只在Composite里面聲明所有的用來管理子類對(duì)象的方法(如下圖所示)纽哥。這樣就避免了上一種方式的安全性問題,但是由于葉子和分支有不同的接口栖秕,所以又失去了透明性春塌。


安全性UML.jpg
《設(shè)計(jì)模式》一書認(rèn)為:在這一模式中,相對(duì)于安全性,我們比較強(qiáng)調(diào)透明性只壳。對(duì)于第一種方式中葉子節(jié)點(diǎn)內(nèi)不需要的方法可以使用空處理或者異常報(bào)告的方式來解決俏拱。

這里在看的時(shí)候也看到兩個(gè)不錯(cuò)的實(shí)例,一個(gè)是針對(duì)公司吼句、部門的實(shí)例锅必。另外一個(gè)是在Android中View和ViewGroup的例子,都是組合模式的代表惕艳。這里我想到了Dota中的一個(gè)場(chǎng)景搞隐。Dota中以英雄做核心,英雄又分為力量远搪、敏捷劣纲、智力,各個(gè)類型的英雄又有很多個(gè)實(shí)現(xiàn)谁鳍。

1味廊、抽象所有英雄的操作HeroComponent接口

public abstract class HeroCompnent {
    /**
     * 添加
     */
    public abstract void add(HeroCompnent heroCompnent);
    /**
     * 移動(dòng)
     */
    public abstract void move();
    /**
     * 攻擊
     */
    public abstract void attack();
}

2、定義葉子節(jié)點(diǎn)棠耕,比如實(shí)現(xiàn)一個(gè)英雄-影魔

/**
 * 影魔類
 * @author Iflytek_dsw
 *
 */
public class YaphetsLeaf extends HeroCompnent{

    
    @Override
    public void move() {
        System.out.println("Yaphets move");
    }

    @Override
    public void attack() {
        System.out.println("Yaphets attack");
    }

    @Override
    public void add(HeroCompnent heroCompnent) {
        //這里是一個(gè)缺省的方法
    }

}

3、定義智力英雄

/**
 * 智力英雄
 * @author Iflytek_dsw
 *
 */
class IntellectualHero extends HeroCompnent{
    private List<HeroCompnent> listIntell = new ArrayList<>();
    public IntellectualHero(){
    }
    
    @Override
    public void move() {
        for(HeroCompnent tempCompnent : listIntell){
            tempCompnent.move();
        }
    }

    @Override
    public void attack() {
        for(HeroCompnent tempCompnent : listIntell){
            tempCompnent.attack();
        }
    }

    @Override
    public void add(HeroCompnent heroCompnent) {
        listIntell.add(heroCompnent);
    }
}

/**
 * 沉默術(shù)士
 * @author Iflytek_dsw
 *
 */
class SilenceHero extends IntellectualHero{

    @Override
    public void move() {
        System.out.println("SilenceHero move");
    }

    @Override
    public void attack() {
        System.out.println("SilenceHero attack");
    }
}

/**
 * 食人魔法師
 * @author Iflytek_dsw
 *
 */
class AggronStonebreaker extends IntellectualHero{
    @Override
    public void move() {
        System.out.println("AggronStonebreaker move");
    }

    @Override
    public void attack() {
        System.out.println("AggronStonebreaker attack");
    }
}

4柠新、定義所有英雄的Compsite

/**
 * 所有的英雄
 * @author Iflytek_dsw
 *
 */
public class HeroCompsite extends HeroCompnent {
    private List<HeroCompnent> listHeroCompsite = new ArrayList<HeroCompnent>();
    
    @Override
    public void add(HeroCompnent heroCompnent) {
        listHeroCompsite.add(heroCompnent);
    }

    @Override
    public void move() {
        for(HeroCompnent tempCompnent : listHeroCompsite){
            tempCompnent.move();
        }
    }

    @Override
    public void attack() {
        for(HeroCompnent tempCompnent : listHeroCompsite){
            tempCompnent.attack();
        }
    }
}

定義客戶端

public class Client {
    public static void main(String []args){
        /**
         * 首先窍荧,我們也需要明確一點(diǎn),我們把這些邏輯設(shè)計(jì)好恨憎,但是他們之間的關(guān)系蕊退、組裝還是需要單獨(dú)維護(hù)的。
         * 不然如果新增一個(gè)種類憔恳,都去在Compsite中維護(hù)顯然違背了面向?qū)ο蟮脑O(shè)計(jì)原則瓤荔,改動(dòng)過大。
         */
        
        
        //客戶想看看影魔的攻擊
        HeroCompnent yaphetsLeaf = new YaphetsLeaf();
        yaphetsLeaf.attack();
        
        //客戶想看下沉默術(shù)士的移動(dòng)效果
        HeroCompnent silence = new SilenceHero();
        silence.move();
        
        //客戶想了解下所有智力英雄的攻擊效果
        IntellectualHero intellectualHero = new IntellectualHero();
        intellectualHero.add(new SilenceHero());
        intellectualHero.add(new AggronStonebreaker());
        intellectualHero.attack();
    }
}

在上面的例子中钥组,我們能看到組合模式可以很靈活的組合成我們需要的操作输硝。只需要把關(guān)系理清楚,然后組合好程梦〉惆眩客戶端只需要進(jìn)行按照需要添加元素來進(jìn)行操作,不需要關(guān)注邏輯關(guān)系屿附。

總結(jié)
在學(xué)習(xí)組合模式過程中郎逃,看了網(wǎng)上很多文章的介紹,但總是理解的不是很透徹挺份“玻總是理解“整體-部分”的概念理解不是很透徹。這個(gè)整體理解也是一個(gè)大種類,這個(gè)大類里面可以包含很多小類优训,操作這個(gè)類別的時(shí)候朵你,直接操作這個(gè)整體。

維護(hù)一個(gè)技術(shù)更新確實(shí)非常難型宙,但是看到大家的點(diǎn)贊撬呢、收藏很開心,希望大家多多支持妆兑。同時(shí)歡迎大家留言交流魂拦,共同進(jìn)步。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末搁嗓,一起剝皮案震驚了整個(gè)濱河市芯勘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌腺逛,老刑警劉巖荷愕,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異棍矛,居然都是意外死亡安疗,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門够委,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荐类,“玉大人,你說我怎么就攤上這事茁帽∮窆蓿” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵潘拨,是天一觀的道長吊输。 經(jīng)常有香客問我,道長铁追,這世上最難降的妖魔是什么季蚂? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮琅束,結(jié)果婚禮上癣蟋,老公的妹妹穿的比我還像新娘。我一直安慰自己狰闪,他們只是感情好疯搅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著埋泵,像睡著了一般幔欧。 火紅的嫁衣襯著肌膚如雪罪治。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天礁蔗,我揣著相機(jī)與錄音觉义,去河邊找鬼。 笑死浴井,一個(gè)胖子當(dāng)著我的面吹牛晒骇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播磺浙,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼洪囤,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了撕氧?” 一聲冷哼從身側(cè)響起瘤缩,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伦泥,沒想到半個(gè)月后剥啤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡不脯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年府怯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片防楷。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡富腊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出域帐,到底是詐尸還是另有隱情,我是刑警寧澤是整,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布肖揣,位于F島的核電站,受9級(jí)特大地震影響瞻凤,放射性物質(zhì)發(fā)生泄漏酌畜。R本人自食惡果不足惜抬伺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望彤断。 院中可真熱鬧,春花似錦易迹、人聲如沸宰衙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽供炼。三九已至一屋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間袋哼,已是汗流浹背冀墨。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留涛贯,地道東北人诽嘉。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像弟翘,于是被迫代替她去往敵國和親虫腋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

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

  • 目錄 本文的結(jié)構(gòu)如下: 引言 什么是組合模式 模式的結(jié)構(gòu) 典型代碼 代碼示例 優(yōu)點(diǎn)和缺點(diǎn) 適用環(huán)境 模式應(yīng)用 一衅胀、...
    w1992wishes閱讀 888評(píng)論 0 2
  • 定義 屬于對(duì)象的結(jié)構(gòu)模式岔乔,有時(shí)又叫做“部分——整體”模式。組合模式將對(duì)象組織到樹結(jié)構(gòu)中滚躯,可以用來描述整體和部分的關(guān)...
    步積閱讀 3,337評(píng)論 2 7
  • 繼承是is-a的關(guān)系雏门。組合和聚合有點(diǎn)像,有些書上沒有作區(qū)分掸掏,都稱之為has-a茁影,有些書上對(duì)其進(jìn)行了較為嚴(yán)格區(qū)分,組...
    時(shí)待吾閱讀 459評(píng)論 0 1
  • 介紹 這篇主要講述設(shè)計(jì)模式中的組合模式丧凤。組合模式又叫部分整體模式募闲,是用于把一組相似的對(duì)象當(dāng)作一個(gè)單一的對(duì)象。組合模...
    東西的南北閱讀 336評(píng)論 0 1
  • 定義 組合模式允許你將對(duì)象組合成樹形結(jié)構(gòu)來表現(xiàn)”部分-整體“的層次結(jié)構(gòu)愿待,使得客戶以一致的方式處理單個(gè)對(duì)象以及對(duì)象的...
    充滿活力的早晨閱讀 301評(píng)論 0 1