C++設(shè)計(jì)模式之組合模式
問(wèn)題描述
上圖,是一個(gè)公司的組織結(jié)構(gòu)圖,總部下面有多個(gè)子公司,同時(shí)總部也有各個(gè)部門(mén),子公司下面有多個(gè)部門(mén)。如果對(duì)這樣的公司開(kāi)發(fā)一個(gè)OA系統(tǒng),作為程序員的你,如何設(shè)計(jì)這個(gè)OA系統(tǒng)呢?先不說(shuō)如何設(shè)計(jì)實(shí)現(xiàn),接著往下看,看完了下面的內(nèi)容,再回過(guò)頭來(lái)想怎么設(shè)計(jì)這樣的OA系統(tǒng)。
什么是組合模式?
在GOF的《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》一書(shū)中對(duì)組合模式是這樣說(shuō)的:將對(duì)象組合成樹(shù)形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。組合(Composite)模式使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。
組合模式(Composite)將小對(duì)象組合成樹(shù)形結(jié)構(gòu),使用戶操作組合對(duì)象如同操作一個(gè)單個(gè)對(duì)象。組合模式定義了“部分-整體”的層次結(jié)構(gòu),基本對(duì)象可以被組合成更大的對(duì)象,而且這種操作是可重復(fù)的,不斷重復(fù)下去就可以得到一個(gè)非常大的組合對(duì)象,但這些組合對(duì)象與基本對(duì)象擁有相同的接口,因而組合是透明的,用法完全一致。
我們這樣來(lái)簡(jiǎn)單的理解組合模式,組合模式就是把一些現(xiàn)有的對(duì)象或者元素,經(jīng)過(guò)組合后組成新的對(duì)象,新的對(duì)象提供內(nèi)部方法,可以讓我們很方便的完成這些元素或者內(nèi)部對(duì)象的訪問(wèn)和操作。我們也可以把組合對(duì)象理解成一個(gè)容器,容器提供各種訪問(wèn)其內(nèi)部對(duì)象或者元素的API,我們只需要使用這些方法就可以操作它了。
UML類(lèi)圖
Component:
1.為組合中的對(duì)象聲明接口;
2.在適當(dāng)?shù)那闆r下,實(shí)現(xiàn)所有類(lèi)共有接口的缺省行為;
3.聲明一個(gè)接口用于訪問(wèn)和管理Component的子組件。
Leaf:
1.在組合中表示葉節(jié)點(diǎn)對(duì)象,葉節(jié)點(diǎn)沒(méi)有子節(jié)點(diǎn);
2.在組合中定義葉節(jié)點(diǎn)的行為。
Composite:
1.定義有子部件的那些部件的行為;
2.存儲(chǔ)子部件。
Client:
3.通過(guò)Component接口操作組合部件的對(duì)象。
代碼實(shí)現(xiàn)
/*
** FileName : CompositePatternDemo
** Author : Jelly Young
** Date : 2013/12/09
** Description : More information, please go to //www.jb51.net
*/
#include <iostream>
#include <string>
#include <vector>
using namespace std;
// 抽象的部件類(lèi)描述將來(lái)所有部件共有的行為
class Component
{
public:
Component(string name) : m_strCompname(name){}
virtual ~Component(){}
virtual void Operation() = 0;
virtual void Add(Component *) = 0;
virtual void Remove(Component *) = 0;
virtual Component *GetChild(int) = 0;
virtual string GetName()
{
return m_strCompname;
}
virtual void Print() = 0;
protected:
string m_strCompname;
};
class Leaf : public Component
{
public:
Leaf(string name) : Component(name)
{}
void Operation()
{
cout<<"I'm "<<m_strCompname<<endl;
}
void Add(Component *pComponent){}
void Remove(Component *pComponent){}
Component *GetChild(int index)
{
return NULL;
}
void Print(){}
};
class Composite : public Component
{
public:
Composite(string name) : Component(name)
{}
~Composite()
{
vector<Component *>::iterator it = m_vecComp.begin();
while (it != m_vecComp.end())
{
if (*it != NULL)
{
cout<<"----delete "<<(*it)->GetName()<<"----"<<endl;
delete *it;
*it = NULL;
}
m_vecComp.erase(it);
it = m_vecComp.begin();
}
}
void Operation()
{
cout<<"I'm "<<m_strCompname<<endl;
}
void Add(Component *pComponent)
{
m_vecComp.push_back(pComponent);
}
void Remove(Component *pComponent)
{
for (vector<Component *>::iterator it = m_vecComp.begin(); it != m_vecComp.end(); ++it)
{
if ((*it)->GetName() == pComponent->GetName())
{
if (*it != NULL)
{
delete *it;
*it = NULL;
}
m_vecComp.erase(it);
break;
}
}
}
Component *GetChild(int index)
{
if (index > m_vecComp.size())
{
return NULL;
}
return m_vecComp[index - 1];
}
void Print()
{
for (vector<Component *>::iterator it = m_vecComp.begin(); it != m_vecComp.end(); ++it)
{
cout<<(*it)->GetName()<<endl;
}
}
private:
vector<Component *> m_vecComp;
};
int main(int argc, char *argv[])
{
Component *pNode = new Composite("Beijing Head Office");
Component *pNodeHr = new Leaf("Beijing Human Resources Department");
Component *pSubNodeSh = new Composite("Shanghai Branch");
Component *pSubNodeCd = new Composite("Chengdu Branch");
Component *pSubNodeBt = new Composite("Baotou Branch");
pNode->Add(pNodeHr);
pNode->Add(pSubNodeSh);
pNode->Add(pSubNodeCd);
pNode->Add(pSubNodeBt);
pNode->Print();
Component *pSubNodeShHr = new Leaf("Shanghai Human Resources Department");
Component *pSubNodeShCg = new Leaf("Shanghai Purchasing Department");
Component *pSubNodeShXs = new Leaf("Shanghai Sales department");
Component *pSubNodeShZb = new Leaf("Shanghai Quality supervision Department");
pSubNodeSh->Add(pSubNodeShHr);
pSubNodeSh->Add(pSubNodeShCg);
pSubNodeSh->Add(pSubNodeShXs);
pSubNodeSh->Add(pSubNodeShZb);
pNode->Print();
// 公司不景氣,需要關(guān)閉上海質(zhì)量監(jiān)督部門(mén)
pSubNodeSh->Remove(pSubNodeShZb);
if (pNode != NULL)
{
delete pNode;
pNode = NULL;
}
return 0;
}
實(shí)現(xiàn)要點(diǎn)
1.Composite的關(guān)鍵之一在于一個(gè)抽象類(lèi),它既可以代表Leaf,又可以代表Composite;所以在實(shí)際實(shí)現(xiàn)時(shí),應(yīng)該最大化Component接口,Component類(lèi)應(yīng)為L(zhǎng)eaf和Composite類(lèi)盡可能多定義一些公共操作。Component類(lèi)通常為這些操作提供缺省的實(shí)現(xiàn),而Leaf和Composite子類(lèi)可以對(duì)它們進(jìn)行重定義;
2.Component是否應(yīng)該實(shí)現(xiàn)一個(gè)Component列表,在上面的代碼中,我是在Composite中維護(hù)的列表,由于在Leaf中,不可能存在子Composite,所以在Composite中維護(hù)了一個(gè)Component列表,這樣就減少了內(nèi)存的浪費(fèi);
3.內(nèi)存的釋放;由于存在樹(shù)形結(jié)構(gòu),當(dāng)父節(jié)點(diǎn)都被銷(xiāo)毀時(shí),所有的子節(jié)點(diǎn)也必須被銷(xiāo)毀,所以,我是在析構(gòu)函數(shù)中對(duì)維護(hù)的Component列表進(jìn)行統(tǒng)一銷(xiāo)毀,這樣就可以免去客戶端頻繁銷(xiāo)毀子節(jié)點(diǎn)的困擾;
4.由于在Component接口提供了最大化的接口定義,導(dǎo)致一些操作對(duì)于Leaf節(jié)點(diǎn)來(lái)說(shuō)并不適用,比如:Leaf節(jié)點(diǎn)并不能進(jìn)行Add和Remove操作,由于Composite模式屏蔽了部分與整體的區(qū)別,為了防止客戶對(duì)Leaf進(jìn)行非法的Add和Remove操作,所以,在實(shí)際開(kāi)發(fā)過(guò)程中,進(jìn)行Add和Remove操作時(shí),需要進(jìn)行對(duì)應(yīng)的判斷,判斷當(dāng)前節(jié)點(diǎn)是否為Composite。
組合模式的優(yōu)點(diǎn)
將對(duì)象組合成樹(shù)形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。組合模式使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。
使用場(chǎng)景
1.你想表示對(duì)象的部分-整體層次結(jié)構(gòu);
2.希望用戶忽略組合對(duì)象與單個(gè)對(duì)象的不同,用戶將統(tǒng)一地使用組合結(jié)構(gòu)中的所有對(duì)象。
引用大話設(shè)計(jì)模式的片段:“當(dāng)發(fā)現(xiàn)需求中是體現(xiàn)部分與整體層次結(jié)構(gòu)時(shí),以及你希望用戶可以忽略組合對(duì)象與單個(gè)對(duì)象的不同,統(tǒng)一地使用組合結(jié)構(gòu)中的所有對(duì)象時(shí),就應(yīng)該考慮組合模式了?!?/p>
總結(jié)
通過(guò)上面的簡(jiǎn)單講解,我們知道了,組合模式意圖是通過(guò)整體與局部之間的關(guān)系,通過(guò)樹(shù)形結(jié)構(gòu)的形式進(jìn)行組織復(fù)雜對(duì)象,屏蔽對(duì)象內(nèi)部的細(xì)節(jié),對(duì)外展現(xiàn)統(tǒng)一的方式來(lái)操作對(duì)象,是我們處理更復(fù)雜對(duì)象的一個(gè)手段和方式?,F(xiàn)在再結(jié)合上面的代碼,想想文章開(kāi)頭提出的公司OA系統(tǒng)如何進(jìn)行設(shè)計(jì)。
上一篇:C++在成員函數(shù)中使用STL的find_if函數(shù)實(shí)例
欄 目:C語(yǔ)言
下一篇:沒(méi)有了
本文標(biāo)題:C++設(shè)計(jì)模式之組合模式
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/3317.html
您可能感興趣的文章
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 01-10深入理解C++中常見(jiàn)的關(guān)鍵字含義
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10APUE筆記之:進(jìn)程環(huán)境詳解
- 01-10c++中inline的用法分析
- 01-10用C++實(shí)現(xiàn)DBSCAN聚類(lèi)算法
- 01-10全排列算法的非遞歸實(shí)現(xiàn)與遞歸實(shí)現(xiàn)的方法(C++)
- 01-10C++大數(shù)模板(推薦)
- 01-10淺談C/C++中的static與extern關(guān)鍵字的使用詳解
- 01-10深入C/C++浮點(diǎn)數(shù)在內(nèi)存中的存儲(chǔ)方式詳解


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫(xiě)分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫(xiě)函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 04-02jquery與jsp,用jquery
- 01-10delphi制作wav文件的方法
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子