大牧絮叨設(shè)計(jì)模式:合成模式/組合模式

1斟叼、 合成模式概述1.1、 核心組件1.2煤蹭、 優(yōu)點(diǎn)缺陷2、 Java實(shí)現(xiàn)1)組件接口規(guī)范2)組件實(shí)現(xiàn)3)實(shí)現(xiàn)測試4)測試結(jié)果3川梅、 Python實(shí)現(xiàn)4疯兼、 Go實(shí)現(xiàn)1) 合成/組合模式:抽象接口2) Leaf組件實(shí)現(xiàn)3) Composite實(shí)現(xiàn)4) 關(guān)于GO

1、 合成模式概述

合成模式[Composite]也稱為部分-整體模式[Part-Whole]贫途、組合模式吧彪,合成模式中將對象組織到樹形結(jié)構(gòu)中,針對同一種對象描述整體和部分的關(guān)系丢早,合成模式下可以將簡單對象和組合對象同等對待姨裸。

提到合成模式秧倾,總會想起這樣一個故事 從前有座山,山里有座廟傀缩,廟里有個老和尚那先,廟里有個小和尚,老和尚給小和尚講故事赡艰,講的什么故事呢售淡?從前有座山…

隨筆涂鴉慷垮,不要見笑

在項(xiàng)目開發(fā)的某些情況下需要類似樹形結(jié)構(gòu)的對象架構(gòu)揖闸,如項(xiàng)目中常規(guī)的組織結(jié)構(gòu)關(guān)系,權(quán)限管理關(guān)系料身、文件目錄結(jié)構(gòu)等等汤纸,都需要通過類似樹形結(jié)構(gòu)的軟件架構(gòu)進(jìn)行定義,合成模式就是針對這樣的結(jié)構(gòu)的一種通用解決方案芹血。

1.1贮泞、 核心組件

合成模式中核心主要包含兩部分組件,包含下級節(jié)點(diǎn)的組件和不包含下級節(jié)點(diǎn)的組件幔烛,如果形容成一個樹形結(jié)構(gòu)的話我們稱為 樹枝節(jié)點(diǎn)樹葉節(jié)點(diǎn)啃擦。

image.png

合成模式中,根據(jù)樹枝節(jié)點(diǎn)和樹葉節(jié)點(diǎn)兩種節(jié)點(diǎn)的是否一致性说贝,區(qū)分為透明形式安全形式议惰,不論哪種處理形式都是通過組件的嵌套組合完成部分-整體的關(guān)聯(lián)關(guān)系慎颗,通過這樣的關(guān)聯(lián)關(guān)系表達(dá)樹形結(jié)構(gòu)乡恕。

1.2、 優(yōu)點(diǎn)缺陷

優(yōu)點(diǎn):

高層模塊調(diào)用簡單俯萎, 節(jié)點(diǎn)自由增加傲宜。

缺陷:

在使用組合模式時,其葉子和樹枝的聲明都是實(shí)現(xiàn)類夫啊,而不是接口函卒,違反了依賴倒置原則,同時不容易限制組合中的組件撇眯。

2报嵌、 Java實(shí)現(xiàn)

1)組件接口規(guī)范

package com.damu;

import com.sun.org.apache.xpath.internal.operations.String;

import java.util.List;

/**
 * <p>項(xiàng)目文檔: 合成模式 接口規(guī)范 </p>
 *
 * @author <a >大牧</a>
 * @version V1.0
 */
public interface IComponent {
    /**
     * 增加節(jié)點(diǎn)
     * @param component 要增加的節(jié)點(diǎn)對象
     */
    IComponent add(IComponent component);

    /**
     * 刪除節(jié)點(diǎn)
     * @param component 要刪除的節(jié)點(diǎn)對象
     */
    IComponent remove(IComponent component);

    /**
     * 判斷是否包含子節(jié)點(diǎn)
     * @return 返回判斷結(jié)果
     */
    Boolean hasChildComponent();

    /**
     * 獲取自身節(jié)點(diǎn)
     * @return 返回當(dāng)前節(jié)點(diǎn)
     */
    IComponent getComponentSelf();

    /**
     * 獲取所有子節(jié)點(diǎn)
     * @return 所有子節(jié)點(diǎn)
     */
    List<IComponent> getComponentsChild();

    /**
     * 遍歷節(jié)點(diǎn)信息
     */
    static void lookUpComponent(IComponent component, Integer depth) {
        StringBuffer sb = new StringBuffer("");
        for (int i = 0; i < depth; i++) {
            sb.append("--");
        }

        if (component.hasChildComponent()) {
            System.out.println(sb + "Composite: " + ((Composite)component).getData());
            // 獲取所有子節(jié)點(diǎn)
            for (IComponent childComponent : component.getComponentsChild()) {
                IComponent.lookUpComponent(childComponent, depth + 2);
            }
            return;
        }
        System.out.println(sb + "Leaf: " + ((Composite)component).getData());
    }
}

2)組件實(shí)現(xiàn)

package com.damu;

import java.util.List;
import java.util.Vector;

/**
 * <p>項(xiàng)目文檔: 樹枝節(jié)點(diǎn) </p>
 *
 * @author <a >大牧</a>
 * @version V1.0
 */
public class Composite implements IComponent {

    // 子節(jié)點(diǎn)集合
    private Vector<IComponent> vector = new Vector<IComponent>();
    // 當(dāng)前節(jié)點(diǎn)數(shù)據(jù)
    private String data;

    public Composite(String data) {
        this.data = data;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    @Override
    public IComponent add(IComponent component) {
        this.vector.add(component);
        return this;
    }

    @Override
    public IComponent remove(IComponent component) {
        this.vector.remove(component);
        return this;
    }

    @Override
    public Boolean hasChildComponent() {
        return this.vector.size() > 0;
    }

    @Override
    public IComponent getComponentSelf() {
        return this;
    }

    @Override
    public List<IComponent> getComponentsChild() {
        return this.vector;
    }
}

3)實(shí)現(xiàn)測試

package com.damu;

/**
 * <p>項(xiàng)目文檔: 合成模式 透明狀態(tài) 測試代碼</p>
 *
 * @author <a >大牧</a>
 * @version V1.0
 */
public class CompositeMain {

    public static void main(String[] args) {
        Composite story = new Composite("開始講故事...");

        Composite mount = new Composite("從前有座山");
        Composite temple = new Composite("山里有座廟");
        Composite buddhistMonk = new Composite("廟里有個老和尚");
        Composite childBuddhistMonk = new Composite("廟里有個小和尚");

        // 從前有座山...loop 1 -> n
        IComponent thisStory = story.add(mount).add(temple.add(buddhistMonk).add(childBuddhistMonk));
        // 遍歷查看
        IComponent.lookUpComponent(thisStory, 0);

        System.out.println(" ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~");

        // 組織關(guān)系
        Composite ali = new Composite("阿里總部");
        Composite hz = new Composite("杭州服務(wù)部");
        Composite sh = new Composite("上海營銷部");
        Composite bj = new Composite("北京技術(shù)部");

        Composite hz01 = new Composite("電商服務(wù)部");
        Composite hz02 = new Composite("營銷服務(wù)部");

        Composite sh01 = new Composite("營銷策劃部");
        Composite sh02 = new Composite("營銷推廣部");

        Composite bj01 = new Composite("秒殺技術(shù)組");
        Composite bj02 = new Composite("搶購技術(shù)組");
        Composite bj03 = new Composite("推薦平臺組");

        ali.add(hz.add(hz01).add(hz02))
            .add(sh.add(sh01).add(sh02))
            .add(bj.add(bj01).add(bj02).add(bj03));

        IComponent.lookUpComponent(ali, 0);
    }
}

4)測試結(jié)果

合成模式,也稱為組合模式熊榛,通過類型自身的組合關(guān)系表達(dá)了部分-整體的邏輯結(jié)構(gòu)锚国,上述代碼運(yùn)行結(jié)果:

Composite: 開始講故事...
----Leaf: 從前有座山
----Composite: 山里有座廟
--------Leaf: 廟里有個老和尚
--------Leaf: 廟里有個小和尚
 ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~
Composite: 阿里總部
----Composite: 杭州服務(wù)部
--------Leaf: 電商服務(wù)部
--------Leaf: 營銷服務(wù)部
----Composite: 上海營銷部
--------Leaf: 營銷策劃部
--------Leaf: 營銷推廣部
----Composite: 北京技術(shù)部
--------Leaf: 秒殺技術(shù)組
--------Leaf: 搶購技術(shù)組
--------Leaf: 推薦平臺組

3、 Python實(shí)現(xiàn)

"""
設(shè)計(jì)模式——組合模式
組合模式(Composite Pattern):將對象組合成成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu),組合模式使得用戶對單個對象和組合對象的使用具有一致性.
"""

# 抽象一個組織類
class Component(object):

    def __init__(self, name):
        self.name = name

    def add(self,comp):
        raise NotImplementedError("該方法必須在子類中實(shí)現(xiàn)")

    def remove(self,comp):
        raise NotImplementedError("該方法必須在子類中實(shí)現(xiàn)")

    def lookup(self, depth):
        raise NotImplementedError("該方法必須在子類中實(shí)現(xiàn)")

# 葉子節(jié)點(diǎn)
class Leaf(Component):

    def add(self,comp):
        print('不能添加下級節(jié)點(diǎn)')

    def remove(self,comp):
        print('不能刪除下級節(jié)點(diǎn)')

    def lookup(self, depth):
        strtemp = ''
        for i in range(depth):
            strtemp += strtemp + '-'
        print strtemp+self.name


# 枝節(jié)點(diǎn)
class Composite(Component):

    def __init__(self, name):
        self.name = name
        self.children = list()

    def add(self,comp):
        self.children.append(comp)

    def remove(self,comp):
        self.children.remove(comp)

    def lookup(self, depth):
        strtemp = ''
        
        for i in range(depth):
            strtemp += strtemp+'-'
        print(strtemp + self.name)
        
        for comp in self.children:
            comp.display(depth + 2)

if __name__ == "__main__":
    #生成樹根
    root = Composite("root")
    #根上長出2個葉子
    root.add(Leaf('leaf A'))
    root.add(Leaf('leaf B'))

    #根上長出樹枝Composite X
    comp = Composite("Composite X")
    comp.add(Leaf('leaf XA'))
    comp.add(Leaf('leaf XB'))
    root.add(comp)

    #根上長出樹枝Composite X
    comp2 = Composite("Composite XY")
    #Composite X長出2個葉子
    comp2.add(Leaf('leaf XYA'))
    comp2.add(Leaf('leaf XYB'))
    root.add(comp2)
    # 根上又長出2個葉子,C和D,D沒張昊,掉了
    root.add(Leaf('Leaf C'))
    leaf = Leaf("Leaf D")
    root.add(leaf)
    root.remove(leaf)
    #展示組織
    root.lookup(1)

4玄坦、 Go實(shí)現(xiàn)

1) 合成/組合模式:抽象接口

type IComponent interface {
    Name() string
    Description() string
    Price() float32
    LookUp()

    Add(IComponent)
    Remove(int)
    Child(int) IComponent
}

2) Leaf組件實(shí)現(xiàn)

type Leaf struct {
    name        string
    description string
    price       float32
}

func Leaf(name, description string, price float32) IComponent {
    return &Leaf{
        name:        name,
        description: description,
        price:       price,
    }
}

func (m *Leaf) Name() string {
    return m.name
}

func (m *Leaf) Description() string {
    return m.description
}

func (m *Leaf) Price() float32 {
    return m.price
}

func (m *Leaf) Lookup() {
    fmt.Printf("  %s, ¥%.2f\n", m.name, m.price)
    fmt.Printf("    -- %s\n", m.description)
}

func (m *Leaf) Add(IComponent) {
    panic("樹葉節(jié)點(diǎn)血筑,不包含該方法")
}

func (m *Leaf) Remove(int) {
    panic("樹葉節(jié)點(diǎn)绘沉,不包含該方法")
}

func (m *Leaf) Child(int) IComponent {
    panic("樹葉節(jié)點(diǎn),不包含該方法")
}

3) Composite實(shí)現(xiàn)

type Composite struct {
    name        string
    description string
    children    []IComponent
}

func NewMenu(name, description string) IComponent {
    return &Composite{
        name:        name,
        description: description,
    }
}

func (m *Composite) Name() string {
    return m.name
}

func (m *Composite) Description() string {
    return m.description
}

func (m *Composite) Price() (price float32) {
    for _, v := range m.children {
        price += v.Price()
    }
    return
}

func (m *Composite) Print() {
    fmt.Printf("%s, %s, ¥%.2f\n", m.name, m.description, m.Price())
    fmt.Println("------------------------")
    for _, v := range m.children {
        v.Print()
    }
    fmt.Println()
}

func (m *Composite) Add(c IComponent) {
    m.children = append(m.children, c)
}

func (m *Composite) Remove(idx int) {
    m.children = append(m.children[:idx], m.children[idx+1:]...)
}

func (m *Composite) Child(idx int) IComponent {
    return m.children[idx]
}

4) 關(guān)于GO

其實(shí)更多時候Go語言的定位不是如此繁復(fù)的業(yè)務(wù)處理邏輯豺总,而是數(shù)據(jù)結(jié)構(gòu)的直觀描述车伞,類似合成設(shè)計(jì)模式這樣的結(jié)構(gòu)模式,在Go語言中應(yīng)該直接通過組合的方式將不同的數(shù)據(jù)進(jìn)行規(guī)范定義即可喻喳,沒有必要為賦新詞強(qiáng)說愁另玖,沒有那么多接口沒有那么多繼承,只是簡單的通過不同復(fù)雜數(shù)據(jù)的組合方式完成即可表伦。這一點(diǎn)上日矫,上述代碼就顯得非常不友好了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末绑榴,一起剝皮案震驚了整個濱河市哪轿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌翔怎,老刑警劉巖窃诉,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異赤套,居然都是意外死亡飘痛,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門容握,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宣脉,“玉大人,你說我怎么就攤上這事剔氏∷懿” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵谈跛,是天一觀的道長羊苟。 經(jīng)常有香客問我,道長感憾,這世上最難降的妖魔是什么蜡励? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮阻桅,結(jié)果婚禮上凉倚,老公的妹妹穿的比我還像新娘。我一直安慰自己嫂沉,他們只是感情好稽寒,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著输瓜,像睡著了一般瓦胎。 火紅的嫁衣襯著肌膚如雪芬萍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天搔啊,我揣著相機(jī)與錄音柬祠,去河邊找鬼。 笑死负芋,一個胖子當(dāng)著我的面吹牛漫蛔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播旧蛾,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼莽龟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了锨天?” 一聲冷哼從身側(cè)響起毯盈,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎病袄,沒想到半個月后搂赋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡益缠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年脑奠,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片幅慌。...
    茶點(diǎn)故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡宋欺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出胰伍,到底是詐尸還是另有隱情齿诞,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布喇辽,位于F島的核電站掌挚,受9級特大地震影響雨席,放射性物質(zhì)發(fā)生泄漏菩咨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一陡厘、第九天 我趴在偏房一處隱蔽的房頂上張望抽米。 院中可真熱鬧,春花似錦糙置、人聲如沸云茸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽标捺。三九已至懊纳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間亡容,已是汗流浹背嗤疯。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留闺兢,地道東北人茂缚。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像屋谭,于是被迫代替她去往敵國和親脚囊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評論 2 359

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

  • 1.初識組合模式 將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)桐磁。組合模式使得用戶對單個對象和組合對象的使用具...
    王偵閱讀 1,066評論 0 2
  • 本文的主要內(nèi)容: 介紹組合模式 示例 組合模式總結(jié) 源碼分析組合模式的典型應(yīng)用java.awt中的組合模式Java...
    小旋鋒的簡書閱讀 1,037評論 0 4
  • 0.提前說明 模式選擇的方法1)模式的功能——看是否能解決問題2)模式的本質(zhì)——看模式是否主要用來解決這類問題3)...
    王偵閱讀 1,060評論 0 1
  • 【學(xué)習(xí)難度:★★★☆☆悔耘,使用頻率:★★★★☆】直接出處:組合模式梳理和學(xué)習(xí):https://github.com/...
    BruceOuyang閱讀 1,000評論 0 1
  • "書是人生的益友,但也僅止于此我擂,人生的路還得自己走淮逊。也許有的人對一本書或一位作家一見傾心,愛之彌篤扶踊,乃至白頭偕老泄鹏,...
    蕙心緣閱讀 412評論 1 2