(Boolan) C++設計模式 第三周筆記(一)

Composite 模式
一、描述
概念:將對象組合成樹形結構以表示“部分-整體”的層次結構谐区。Composite使得用戶對單個對象和組合的使用具有一致性菩貌。

Composite 模式的典型結構圖為:


二箭阶、實例:
大家在上學的時候應該都學過“數(shù)據(jù)結構”這門課程吧,還記得其中有一節(jié)叫“二叉樹”吧,我們上學那會兒這一章節(jié)是必考內容,左子樹,右子樹,什么先序遍歷后序遍歷什么,重點就是二叉樹的的遍歷,我還記得當時老師就說,考試的時候一定有二叉樹的構建和遍歷,現(xiàn)在想起來還是覺的老師是正確的,樹狀結果在實際項目應用的非常廣泛。
咱就先說個最常見的例子,公司的人事管理就是一個典型的樹狀結構,你想想你公司的結構是不是這樣:


老大,往下一層一層的管理,最后到我們這層小兵,很典型的樹狀結構(說明一下,這不是二叉樹,有關二叉樹的定義可以翻翻以前的教科書),我們今天的任務就是要把這個樹狀結構實現(xiàn)出來,并且還要把它遍歷一遍,你要確認你建立的樹是否有問題呀。從這個樹狀結構上分析,有兩種節(jié)點:有分支的節(jié)點(如研發(fā)部經(jīng)理)和無分支的節(jié)點(如員工 A诈乒、員工 D 等),我們增加一點學術術語上去,總經(jīng)理叫做根節(jié)點(是不是想到 XML 中的那個根節(jié)點 root,那就對了),類似研發(fā)部經(jīng)理有分支的節(jié)點叫做樹枝節(jié)點,類似員工 A 的無分支的節(jié)點叫做樹葉節(jié)點,都很形象,三個類型的的節(jié)點,那是不是定義三個類就可以?好,我們按照這個思路走下去,先看我們自己設計的類圖:


這個類圖是初學者最容易想到的類圖(這個類圖有缺陷了),你有沒有發(fā)覺有問題?getInfo 每個接口都有為什么不能抽象出來?Root 類和 Branch 類有什么差別?為什么要定義成兩個接口兩個類?如果我要加一個任職期限,你是不是每個類都需要修改?如果我要后序遍歷(從員工找到他的上級領導)能做嗎?——徹底暈菜了!
問題很多,我們一個一個解決,先說抽象的問題,確實可以吧 IBranch 和 IRoot 合并成一個接口,這個我們先肯定下來,這是個比較大的改動,我們先畫個類圖(類名稍微做下變化):

注釋:
main()喂饥,客戶
CCorpNode,抽象基類或粮,實現(xiàn)基本信息
CBranchNode捞高,樹枝節(jié)點硝岗,實現(xiàn)Addordinate()函數(shù)和GetSubordinate()函數(shù)
CLeafNode,葉子節(jié)點冗尤,IsLeaf屬性總是“true”
說明:組合模式主要是實現(xiàn)在CBranchNode對象里增加對其它對象的數(shù)組贱除,如vector<CCorpNode*>媳溺,數(shù)組里可以存放CBranchNode和CLeafNode對象悬蔽。這樣方便進行遍歷操作。
注意:組合模式有透明組合模式和安全組合模式录语。透明組合模式是將Addordinate和GetSubordinate這兩個函數(shù)也抽象到CCorpNode基類里禾乘,這增加了操作葉子節(jié)點的難度,更易出現(xiàn)邏輯問題蒲稳。所以盡量使用安全模式江耀。
這個簡單了诉植,可以想像一下TreeView和TreeNode基本上是這個意思了,將很多數(shù)據(jù)組織在一塊舌稀。

代碼:
抽象基類壁查,實現(xiàn)基本信息:CorpNode類
CorpNode.h

#ifndef __Composite__CorpNode__  
#define __Composite__CorpNode__  
  
#include <iostream>  
using std::string;  
  
class CCorpNode {  
public:  
    CCorpNode(void);  
    CCorpNode(string _name,string _pos,string _salary);  
    virtual ~CCorpNode(void);  
    virtual string GetInfo();  
    void SetParent(CCorpNode *_pParent);  
    CCorpNode *GetParent();  
    virtual bool IsLeaf() = 0;  
private:  
    string m_name;  
    string m_position;  
    string m_salary;  
protected:  
    bool m_isLeaf;  
    CCorpNode *m_pParent;  
};  
  

CorpNode.cpp

#include "CorpNode.h"  
CCorpNode::CCorpNode(void)  
{  
    m_name = "";  
    m_position = "";  
    m_salary = "0";  
}  
  
CCorpNode::CCorpNode(string _name,string _pos,string _salary):m_name(_name), m_position(_pos), m_salary(_salary)  
{  
      
}  
  
CCorpNode::~CCorpNode(void)  
{  
      
}  
  
string CCorpNode::GetInfo()  
{  
    string info = "";  
    info.append("姓名: ");  
    info.append(this->m_name);  
    info.append("\t職位:");  
    info.append(this->m_position);  
    info.append("\t薪水:");  
    info.append(this->m_salary);  
  
    return info;  
}  
  
void CCorpNode::SetParent(CCorpNode *_pParent)  
{  
    this->m_pParent = _pParent;  
}  
  
CCorpNode * CCorpNode::GetParent()  
{  
    return this->m_pParent;  
}  

樹枝節(jié)點:BranchNode類
BranchNode.h

#ifndef __Composite__BranchNode__  
#define __Composite__BranchNode__  
  
#include <iostream>  
#include "CorpNode.h"  
#include <vector>  
using std::vector;  
using std::string;  
  
class CBranchNode:public CCorpNode  
{  
public:  
    CBranchNode(void);  
    CBranchNode(string name,string pos,string salary);  
    ~CBranchNode(void);  
    void Add(CCorpNode* pcorpNode);  
    vector<CCorpNode*> GetSubordinateInfo();  
    bool IsLeaf();  
private:  
    vector<CCorpNode*> m_subordinateList;  
};  
  

BranchNode.cpp

#include "BranchNode.h"  
  
CBranchNode::CBranchNode(void)  
{  
    m_isLeaf = false;  
}  
  
CBranchNode::CBranchNode(string name ,string pos,string salary):CCorpNode(name,pos,salary)  
{  
    m_isLeaf = false;  
}  
  
CBranchNode::~CBranchNode(void)  
{  
      
}  
  
void CBranchNode::Add(CCorpNode *pcorpNode)  
{  
    pcorpNode->SetParent(this);  
    m_subordinateList.push_back(pcorpNode);  
}  
  
vector<CCorpNode*> CBranchNode::GetSubordinateInfo()  
{  
    return this->m_subordinateList;  
}  
  
bool CBranchNode::IsLeaf()  
{  
    return m_isLeaf;  
}  

葉子節(jié)點:LeafNode類
LeafNode.h

#ifndef __Composite__LeafNode__  
#define __Composite__LeafNode__  
  
#include <iostream>  
#include "CorpNode.h"  
class CLeafNode:public CCorpNode  
{  
public:  
    CLeafNode(void);  
    CLeafNode(string name,string pos,string salary);  
    ~CLeafNode(void);  
    bool IsLeaf();  
};  

LeafNode.cpp

#include "LeafNode.h"  
  
CLeafNode::CLeafNode(void)  
{  
    m_isLeaf = true;  
}  
  
CLeafNode::CLeafNode(string name ,string pos,string salary):CCorpNode(name,pos,salary)  
{  
    m_isLeaf = true;  
}  
  
CLeafNode::~CLeafNode(void)  
{  
      
}  
  
bool CLeafNode::IsLeaf()  
{  
    return m_isLeaf;  
}  

客戶:main主程序
main.cpp

#include <stdio.h>  
#include "CorpNode.h"  
#include "BranchNode.h"  
#include "LeafNode.h"  
#include "CConvert.h"  
using std::cout;  
  
string getTreeInfo(CBranchNode *root)  
{  
    vector<CCorpNode*> subordinateList = root->GetSubordinateInfo();  
    string info = "";  
   
    for (vector<CCorpNode*>::iterator it = subordinateList.begin();it != subordinateList.end();it++)  
    {  
        if ((*it)->IsLeaf())  
        {  
            info = info.append("  "+(*it)->GetInfo()+"\n");  
        }  
  
       else  
        {  
           info = info.append((*it)->GetInfo()+"\n"+getTreeInfo((CBranchNode*)(*it)));  
        }  
    }  
    return info;  
}  
  
  
CBranchNode *compositeCorpTree()  
{  
    //首先產(chǎn)生總經(jīng)理CEO  
    CBranchNode *root = new CBranchNode("王大麻子","總經(jīng)理","100000");  
    //把三個部門經(jīng)理產(chǎn)生出來  
    CBranchNode *developDep = new CBranchNode("劉大瘸子","研發(fā)部門經(jīng)理","10000");  
    CBranchNode *salesDep = new CBranchNode("馬二拐子","銷售部門經(jīng)理","20000");  
    CBranchNode *financeDep = new CBranchNode("趙三駝子","財務部經(jīng)理","10000");  
      
    //再把三個小組長產(chǎn)生出來  
    CBranchNode *firstDevGroup = new CBranchNode("楊三乜斜","開發(fā)一組組長","5000");  
    CBranchNode *secondDevGroup = new CBranchNode("吳大棒槌","開發(fā)二組組長","6000");  
      
    //把所有的小兵都產(chǎn)生出來  
    CLeafNode *a = new CLeafNode("a","開發(fā)人員","2000");  
    CLeafNode *b = new CLeafNode("b","開發(fā)人員","2000");  
    CLeafNode *c = new CLeafNode("c","開發(fā)人員","2000");  
    CLeafNode *d = new CLeafNode("d","開發(fā)人員","2000");  
    CLeafNode *e = new CLeafNode("e","開發(fā)人員","2000");  
    CLeafNode *f = new CLeafNode("f","開發(fā)人員","2000");  
    CLeafNode *g = new CLeafNode("g","開發(fā)人員","2000");  
    CLeafNode *h = new CLeafNode("h","銷售人員","2000");  
    CLeafNode *i = new CLeafNode("i","銷售人員","2000");  
    CLeafNode *j = new CLeafNode("i","財務人員","2000");  
    CLeafNode *k = new CLeafNode("k","CEO秘書","2000");  
    CLeafNode *zhengLaoLiu = new CLeafNode("鄭老六","研發(fā)部副經(jīng)理","2000");  
      
    //開始組裝  
    //CEO下有三個部門經(jīng)理和一個秘書  
      
    root->Add(developDep);  
    root->Add(salesDep);  
    root->Add(financeDep);  
      
    root->Add(k);  
      
    //研發(fā)部經(jīng)理  
    developDep->Add(zhengLaoLiu);  
    developDep->Add(firstDevGroup);  
    developDep->Add(secondDevGroup);  
      
    //看看開發(fā)兩個開發(fā)小組下有什么  
    firstDevGroup->Add(a);  
    firstDevGroup->Add(b);  
    firstDevGroup->Add(c);  
    secondDevGroup->Add(d);  
    secondDevGroup->Add(e);  
    secondDevGroup->Add(f);  
      
    //再看銷售部下的人員情況  
    salesDep->Add(h);  
    salesDep->Add(i);  
      
    //最后一個財務  
    firstDevGroup->Add(j);  
      
    return root;  
      
    delete zhengLaoLiu,k,j,i,h,g,f,e,d,c,b,a,secondDevGroup,firstDevGroup,financeDep,salesDep,developDep,root;  
     
}  
  
int main(int argc, const char * argv[])  
{  
      
      
      
    CBranchNode *CEO =  compositeCorpTree();  
    cout<<CEO->GetInfo()<<std::endl;   
    cout<< getTreeInfo(CEO);  
    // insert code here...  
    //printf("Hello, World!\n");  
    return 0;  
}  

結果如下:

享元模式
一沃暗、描述
設計模式中的享元模式何恶,避免大量擁有相同內容的小類的開銷(如耗費內存),使大家共享一個類(元類).

在面向對象系統(tǒng)的設計何實現(xiàn)中,創(chuàng)建對象是最為常見的操作细层。這里面就有一個問題:如果一個應用程序使用了太多的對象,就會造成很大的存儲開銷。特別是對于大量輕量級(細粒度)的對象,比如在文檔編輯器的設計過程中,我們如果為沒有字母創(chuàng)建一個對象的話,系統(tǒng)可能會因為大量的對象而造成存儲開銷的浪費盛撑。例如一個字母“a”在文檔中出現(xiàn)了100000 次,而實際上我們可以讓這一萬個字母“a”共享一個對象,當然因為在不同的位置可能字母“a”有不同的顯示效果(例如字體和大小等設置不同),在這種情況我們可以為將對象的狀態(tài)分為“外部狀態(tài)”和“內部狀態(tài)”,將可以被共享(不會變化)的狀態(tài)作為內部狀態(tài)存儲在對象中,而外部對象(例如上面提到的字體捧搞、大小等)我們可以在適當?shù)臅r候將外部對象最為參數(shù)傳遞給對象(例如在顯示的時候,將字體胎撇、大小等信息傳遞給對象)。

其典型的結構圖為:

可以從圖 2-1 中看出,Flyweight 模式中有一個類似 Factory 模式的對象構造工廠

FlyweightFactory,當客戶程序員(Client)需要一個對象時候就會向 FlyweightFactory 發(fā)出請求對象的消息 GetFlyweight()消息,FlyweightFactory 擁有一個管理姻采、存儲對象的“倉庫”(或者叫對象池,vector 實現(xiàn)),GetFlyweight()消息會遍歷對象池中的對象,如果已經(jīng)存在則直接返回給 Client,否則創(chuàng)建一個新的對象返回給 Client慨亲。當然可能也有不想被共享的對象(例如結構圖中的 UnshareConcreteFlyweight),但不在本模式的講解范圍,故在實現(xiàn)中不給出纲堵。

二、實例

如上所描述的信息铐望,創(chuàng)建類圖:

注釋:
main:客戶程序員(Client)
FlyweightFactory:“倉庫”(對象池),
Flyweight:對象池中的對象
ConcreteFlyweight:被共享的對象

代碼:
倉庫”(對象池):FlyweightFactory類
FlyweightFactory.h

#ifndef __Flyweight__FlyweightFactory__  
#define __Flyweight__FlyweightFactory__  
  
#include <iostream>  
#include "Flyweight.h"  
#include <string>  
#include <vector>  
#include "ConcreteFlyweight.h"  
using std::cout;  
using std::endl;  
using std::string;  
using std::vector;  
  
class FlyweightFactory  
{  
public:  
    FlyweightFactory();  
    ~FlyweightFactory();  
    Flyweight* GetFlyweight(const string &key);  
private:  
    vector<Flyweight*> _fly;  
      
};  
  

FlyweightFactory.cpp


#include "FlyweightFactory.h"  
  
FlyweightFactory::FlyweightFactory()  
{  
      
}  
  
FlyweightFactory::~FlyweightFactory()  
{  
      
}  
  
Flyweight* FlyweightFactory::GetFlyweight(const string &key)  
{  
    vector<Flyweight*>::iterator it = _fly.begin();  
      
    for (; it != _fly.end(); it++)  
    {  
        if ((*it)->GetIntrinsicState() == key)  
        {  
            cout<<"already created by users...."<<endl;  
            return *it;  
        }  
  
    }  
    Flyweight *fn = new ConcreteFlyweight(key);  
      
    _fly.push_back(fn);  
    return fn;  
      
}  

對象池中的對象:Flyweight類
Flyweight.h

#ifndef __Flyweight__Flyweight__  
#define __Flyweight__Flyweight__  
  
#include <iostream>  
#include <string>  
using std::string;  
  
class Flyweight  
{  
public:  
    Flyweight(void);  
    virtual ~Flyweight(void);  
    virtual void Operation(const string& extrinsicState);  
    string GetIntrinsicState();  
protected:  
    Flyweight(string intrinsicState);  
      
private:  
    string _intrinsicState;  
      
};  
  

Flyweight.cpp

#include "Flyweight.h"  
  
Flyweight::Flyweight(void)  
{  
      
}  
  
Flyweight::Flyweight(string intrinsicState)  
{  
    this->_intrinsicState = intrinsicState;  
}  
  
Flyweight::~Flyweight()  
{  
      
}  
  
void Flyweight::Operation(const string &extrinsicState)  
{  
      
}  
  
string Flyweight::GetIntrinsicState()  
{  
    return this->_intrinsicState;  
}  

被共享的對象:ConcreteFlyweight
ConcreteFlyweight.h


#ifndef __Flyweight__ConcreteFlyweight__  
#define __Flyweight__ConcreteFlyweight__  
  
#include <iostream>  
#include "Flyweight.h"  
class ConcreteFlyweight:public Flyweight  
{  
public:  
    ConcreteFlyweight(void);  
    ConcreteFlyweight(string intrinsicState);  
    ~ConcreteFlyweight();  
    void Operation(const string& extrinsicState);  
      
};  
  

ConcreteFlyweight.cpp


#include "ConcreteFlyweight.h"  
using std::cout;  
using std::endl;  
  
ConcreteFlyweight::ConcreteFlyweight(void)  
{  
      
}  
  
ConcreteFlyweight::ConcreteFlyweight(string intrinsicState)  
{  
    cout<<"ConcreteFlyweight Build....."<<intrinsicState<<endl;  
}  
  
ConcreteFlyweight::~ConcreteFlyweight()  
{  
      
}  
  
void ConcreteFlyweight::Operation(const string &extrinsicState)  
{  
    cout<<"ConcreteFlyweight:內蘊["<<this->GetIntrinsicState()<<"] 外 蘊["<<extrinsicState<<"]"<<endl;  
}  

客戶程序員(Client)
main.cpp

#include <iostream>  
#include "Flyweight.h"  
#include "ConcreteFlyweight.h"  
#include "FlyweightFactory.h"  
using namespace std;  
  
  
int main(int argc, const char * argv[])  
{  
  
    FlyweightFactory *fc = new FlyweightFactory();  
    Flyweight* fw1 = fc->GetFlyweight("hello");  
    Flyweight* fw2 = fc->GetFlyweight("world!");  
    Flyweight* fw3 = fc->GetFlyweight("hello2");  
    // insert code here...  
    std::cout << "Hello, World!\n";  
    return 0;  
}  

結果如下:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末乒验,一起剝皮案震驚了整個濱河市锻全,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鳄厌,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泪漂,死亡現(xiàn)場離奇詭異歪泳,居然都是意外死亡,警方通過查閱死者的電腦和手機敌卓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門假哎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鞍历,“玉大人肪虎,你說我怎么就攤上這事扇救。” “怎么了迅腔?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵沧烈,是天一觀的道長。 經(jīng)常有香客問我蚂夕,道長婿牍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任俏蛮,我火速辦了婚禮上遥,結果婚禮上,老公的妹妹穿的比我還像新娘睬棚。我一直安慰自己解幼,他們只是感情好撵摆,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著暑中,像睡著了一般鲫剿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上雕凹,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天枚抵,我揣著相機與錄音明场,去河邊找鬼。 笑死逼泣,一個胖子當著我的面吹牛,可吹牛的內容都是我干的踱讨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼帚稠!你這毒婦竟也來了滋早?” 一聲冷哼從身側響起砌们,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤浪感,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后揭斧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體峻堰,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡捐名,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了纸型。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梅忌。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡牧氮,死狀恐怖瑰枫,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情尸诽,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站商蕴,受9級特大地震影響绪商,放射性物質發(fā)生泄漏。R本人自食惡果不足惜格郁,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一例书、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧悟耘,春花似錦织狐、人聲如沸移迫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荡陷。三九已至,卻和暖如春徽龟,著一層夾襖步出監(jiān)牢的瞬間唉地,已是汗流浹背传透。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工朱盐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留菠隆,地道東北人浸赫。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像羡榴,于是被迫代替她去往敵國和親运敢。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容

  • 23種設計模式 “對象性能”模式 面向對象很好的解決了“抽象”的問題,但是必不可免地要付出一定的代價羊瘩。對于通常情況...
    孫浩_9bfd閱讀 522評論 0 0
  • 23種設計模式 “對象性能”模式 面向對象很好的解決了“抽象”的問題盼砍,但是必不可免地要付出一定的代價浇坐。對于通常情況...
    孫浩_9bfd閱讀 388評論 0 0
  • 上周講述了DOF設計模式中的“對象創(chuàng)建”模式和“接口隔離”模式,本周講述DOF設計模式中的剩下的模式擒贸,“對象性能”...
    cayhw閱讀 509評論 0 0
  • (一)“對象性能”模式 面向對象很好的解決了“抽象”的問題介劫,但是必不可免地要付出一定的代價案淋。對于通常情況來講,面向...
    Chuankuei閱讀 353評論 0 0
  • 本文是《設計模式——可復用面對對象軟件的基礎》的筆記回右。 面對對象設計的幾個原則:1.針對接口編程漱挚,而不是針對實現(xiàn)編...
    Lension閱讀 1,193評論 0 0