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;
}
結果如下: