本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/i_like_cpp/archive/2004/11/29/197760.aspx
一、功能
將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口,解決兩個(gè)已有接口之間不匹配的問題。Adapter模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
二、結(jié)構(gòu)圖
(1)class adapter
(2)object adapter

三、實(shí)現(xiàn)
和其他很多模式一樣,學(xué)習(xí)設(shè)計(jì)模式的重點(diǎn)是學(xué)習(xí)每種模式的思想,而不應(yīng)拘泥于它的某種具體結(jié)構(gòu)圖和實(shí)現(xiàn)。因?yàn)槟J绞庆`活的,其實(shí)現(xiàn)可以是千變?nèi)f化的,只是所謂萬變不離其宗。 在STL中大量運(yùn)用了Adapter模式,象function adapter、iterator adpter,它們與這里說的adapter結(jié)構(gòu)并不一樣,但思想是一樣的。具體的介紹可到侯捷網(wǎng)站上找相關(guān)文章,他講得非常好。
四、示例代碼
(1)class adapter
namespace DesignPattern_Adapter
{
// class Adaptee
class Adaptee
{
public:
void SpecialRequest() {}
} ;
// class Target
class Target
{
public:
virtual void Request() = 0 ;
} ;
// class Adapter
class Adapter : public Target, private Adaptee
{
public:
virtual void Request() { SpecialRequest() ; }
} ;
}
客戶端代碼:
{
using namespace DesignPattern_Adapter ;
Target *p = new Adapter() ;
p->Request() ; //實(shí)際上調(diào)用的是Adaptee::SpecialRequest()
}
(2)object adapter namespace DesignPattern_Adapter
{
// class Adaptee
class Adaptee
{
public:
void SpecialRequest() {}
} ;
// class Target
class Target
{
public:
virtual void Request() = 0 ;
} ;
// class Adapter
class Adapter : public Target
{
public:
virtual void Request() { _adaptee.SpecialRequest() ; }
private:
Adaptee _adaptee ;
} ;
}
客戶端代碼:
{
using namespace DesignPattern_Adapter ;
Target *p = new Adapter() ;
p->Request() ; //實(shí)際上調(diào)用的是Adaptee::SpecialRequest()
}
六、實(shí)例
(1)STL中的Class Adapter
STL中的Adapter Class包括:a.stack(對應(yīng)的adaptee是deque)。b.queue(對應(yīng)的adaptee是deque)。c.priority_queue(對應(yīng)的adaptee是vector)。 下面是從VC中的< stack >拷出的stack的類定義:
templateclass _Container = deque<_Ty> >
class stack
{ // LIFO queue implemented with a container
public:
typedef _Container container_type;
typedef typename _Container::value_type value_type;
typedef typename _Container::size_type size_type;
stack()
: c()
{ // construct with empty container
}
explicit stack(const _Container& _Cont)
: c(_Cont)
{ // construct by copying specified container
}
bool empty() const
{ // test if stack is empty
return (c.empty());
}
size_type size() const
{ // test length of stack
return (c.size());
}
value_type& top()
{ // return last element of mutable stack
return (c.back());
}
const value_type& top() const
{ // return last element of nonmutable stack
return (c.back());
}
void push(const value_type& _Val)
{ // insert element at end
c.push_back(_Val);
}
void pop()
{ // erase last element
c.pop_back();
}
bool _Eq(const stack<_Ty, _Container>& _Right) const
{ // test for stack equality
return (c == _Right.c);
}
bool _Lt(const stack<_Ty, _Container>& _Right) const
{ // test if this < _Right for stacks
return (c < _Right.c);
}
protected:
_Container c; // the underlying container
};
關(guān)鍵之處在于_Container c,stack所有的操作都轉(zhuǎn)交給c去處理了。(這實(shí)際上就是前面所說的"object adapter",注意STL中的class adapter與上面所說的class adapter概念不完全一致)
stack的使用方法很簡單,如下:
{
int ia[] = { 1,3,2,4 };
deque id(ia, ia+4);
stack is(id);
}
(2)近日看了一篇文章“Generic< Programming >:簡化異常安全代碼”,原文出自http://www.cuj.com/experts/1812/alexandr.htm?topic=experts, 中文譯文出自"C++ View第5期"。 文章絕對一流,作者給出的代碼中也使用了Adaptor模式,也有一定代表性。我將其問題一般化,概括出以下示例:
問題:假設(shè)有幾個(gè)已有類,他們有某些共同的行為,但它們彼此間是獨(dú)立的(沒有共同的基類)。如:
class T1
{
public:
void Proc() {}
} ;
class T2
{
public:
void Proc() {}
} ;
// ...
如何以統(tǒng)一的方式去調(diào)用這些行為呢?
解決方法1:很自然的會想到用模板,如:
template <class T>
void Test(T t)
{
t.Proc() ;
}
的確不錯(cuò),但這只適用于簡單的情況,有時(shí)情況是很復(fù)雜的,比如我們無法把類型放到模板參數(shù)中!
解決方法2:困難來自于這些類沒有共同的基類,所以我們就創(chuàng)造一個(gè)基類,然后再Adapt。
// class IAdaptor,抽象基類
class IAdaptor
{
public:
virtual void Proc() = 0 ;
} ;
// class Adaptor
template <class T>
class Adaptor : public IAdaptor, private T //實(shí)現(xiàn)繼承
{
public:
virtual void Proc() { T::Proc() ; }
} ;
// 以統(tǒng)一方式調(diào)用函數(shù)Proc,而不關(guān)心是T1、T2或其他什么類
void Test(const std::auto_ptr& sp)
{
sp->Proc() ;
}
客戶端代碼:
Test(std::auto_ptr(new Adaptor)) ;
Test(std::auto_ptr(new Adaptor)) ;
上例很簡單,用方法一中的模板函數(shù)就可以很好地解決了。下面是一個(gè)略微復(fù)雜一點(diǎn)的例子,根據(jù)參數(shù)類型來創(chuàng)建適當(dāng)?shù)膶ο螅?/p>
class T1
{
public:
T1(int) { /*...*/ }
void Proc() { /*...*/ }
} ;
class T2
{
public:
T2(char) { /*...*/ }
void Proc() { /*...*/ }
} ;
// class IAdaptor,抽象基類
class IAdaptor
{
public:
virtual void Proc() = 0 ;
} ;
// class Adaptor
template
class Adaptor : public IAdaptor, private T //實(shí)現(xiàn)繼承
{
public:
Adaptor(int n) : T(n) {}
Adaptor(char c) : T(c) {}
virtual void Proc() { T::Proc() ; }
} ;
class Test
{
public:
Test(int n) : sp(new Adaptor(n)) {}
Test(char c) : sp(new Adaptor(c)) {}
void Proc() { sp->Proc() ; }
private:
std::auto_ptr sp ;
} ;
客戶端代碼:
Test t1(10) ;
t1.Proc() ;
Test t2('c') ;
t2.Proc() ;
上面是示例而非實(shí)例,你也許更愿意看看它實(shí)際的運(yùn)用。去下載作者所寫的代碼,好好欣賞一下吧。
C++設(shè)計(jì)模式之Abstract Factory |
|
2002-07-23· · ··COM集中營
|
一、功能 提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無需指定它們具體的類。
二、結(jié)構(gòu)圖
類廠最基本的結(jié)構(gòu)示意圖如下:
在實(shí)際應(yīng)用中,類廠模式可以擴(kuò)充到很復(fù)雜的情況,如下圖所示:

|
三、優(yōu)缺點(diǎn)
優(yōu)點(diǎn):(1)封裝創(chuàng)建過程??蛻舨挥弥李悘S是如何創(chuàng)建類實(shí)例的,類廠封閉了所有創(chuàng)建的細(xì)節(jié)。這樣可選擇不同的創(chuàng)建方法,增加了靈活性。 (2)將客戶與具體類隔離,提高了各自的可重用性。
缺點(diǎn):Factory類層次與具體類層次通常是平行的(即一一對應(yīng)的)。增加一個(gè)具體類,一般也要相應(yīng)地增加一個(gè)factory類,增加了系統(tǒng)復(fù)雜度。
四、實(shí)現(xiàn)
(1)Abstract Factory類中通常是一組Factory Method的集合。個(gè)人認(rèn)為與Factory Method模式?jīng)]有本質(zhì)區(qū)別。
(2)通??梢园压S作為單件。
五、示例代碼
namespace DesignPattern_AbstractFactory
{
class AbstractProductA {}; // Product A
class ProductA1 : public AbstractProductA {};
class ProductA2 : public AbstractProductA {};
class AbstractProductB {}; // Product B
class ProductB1 : public AbstractProductB {};
class ProductB2 : public AbstractProductB {};
class AbstractFactory
{
public:
virtual AbstractProductA* CreateProductA() = 0 ;// 創(chuàng)建ProductA
virtual AbstractProductB* CreateProductB() = 0 ;// 創(chuàng)建ProductB
} ;
class ConcreteFactory1 : public AbstractFactory
{
public:
virtual AbstractProductA* CreateProductA() { return new ProductA1() ; }
virtual AbstractProductB* CreateProductB() { return new ProductB1() ; }
static ConcreteFactory1* Instance() { static ConcreteFactory1 instance ; return &instance ; }
protected:
ConcreteFactory1() {}
private:
ConcreteFactory1(const ConcreteFactory1&) ;
ConcreteFactory1& operator=(const ConcreteFactory1&) ;
} ;
class ConcreteFactory2 : public AbstractFactory
{
public:
virtual AbstractProductA* CreateProductA() { return new ProductA2() ; }
virtual AbstractProductB* CreateProductB() { return new ProductB2() ; }
static ConcreteFactory2* Instance() { static ConcreteFactory2 instance ; return &instance ; }
protected:
ConcreteFactory2() {}
private:
ConcreteFactory2(const ConcreteFactory2&) ;
ConcreteFactory2& operator=(const ConcreteFactory2&) ;
} ;
}
客戶端代碼:
{
using namespace DesignPattern_AbstractFactory ;
// 第一種創(chuàng)建方法
AbstractFactory *pFactory = ConcreteFactory1::Instance() ;
AbstractProductA *pProductA = pFactory->CreateProductA() ;
AbstractProductB *pProductB = pFactory->CreateProductB() ;
// 第二種創(chuàng)建方法
pFactory = ConcreteFactory2::Instance() ;
pProductA = pFactory->CreateProductA() ;
pProductB = pFactory->CreateProductB() ;
}
六、實(shí)例
最早知道類廠的概念是在COM中,但當(dāng)時(shí)也沒想到這是如此重要的一種模式,在許多其他模式中都可以用到類廠模式。 COM中不能直接創(chuàng)建組件,這也是由COM的一個(gè)特性決定的:即客戶不知道要創(chuàng)建的組件的類名。
C++設(shè)計(jì)模式之Singleton |
|
2002-07-26· · ··COM集中營
|
一、功能
保證一個(gè)類僅有一個(gè)實(shí)例。
二、結(jié)構(gòu)圖

|
三、優(yōu)缺點(diǎn)
Singleton模式是做為"全局變量"的替代品出現(xiàn)的。所以它具有全局變量的特點(diǎn):全局可見、貫穿應(yīng)用程序的整個(gè)生命期,它也具有全局變量不具備的性質(zhì):同類型的對象實(shí)例只可能有一個(gè)。
四、實(shí)現(xiàn)
教科書上的Singleton定義如下:
class Singleton
{
public:
static Singleton* Instance() ;
protected:
Singleton() {}
private:
static Singleton *_instance ;
Singleton(const Singleton&) ;
Singleton& operator=(const Singleton&) ;
} ;
Singleton* Singleton::_instance = NULL ;
Singleton* Singleton::Instance()
{
(_instance == NULL) ? _instance = new Singleton() : 0 ; //lazy initialization
return _instance ;
}
(1)因?yàn)榉祷氐氖侵羔?,為防止用戶調(diào)用delete函數(shù),可把static Singleton *_instance;改為在Instance()中定義static Singleton _instance。這樣顯然更安全,同時(shí)也具有l(wèi)azy initialization的特性(即第一次訪問時(shí)才創(chuàng)建)。
(2)假設(shè)需要從Singleton派生子類,而子類也需要有同樣的性質(zhì),既只能創(chuàng)建一個(gè)實(shí)例。我覺得,這很難辦。根本原因在于Instance()函數(shù)不是虛函數(shù),不具有多態(tài)的性質(zhì)。一種常用方法是把Instance()函數(shù)移到子類中,這時(shí)就只能用static Singleton *_instance,而不能用static Singleton _instance了,除非把_instance也要移到子類,無論怎么做都不優(yōu)雅。另一種方法是用模板。具體用什么方法,只能根據(jù)實(shí)際情況權(quán)衡。
五、示例代碼
(1)沒子類的情況
namespace DesignPattern_Singleton
{
class Singleton
{
public:
static Singleton* Instance() { static Singleton _instance ; return &_instance ; }
protected:
Singleton() {}
private:
Singleton(const Singleton&) ;
Singleton& operator=(const Singleton&) ;
} ;
}
客戶端代碼:
{
using namespace DesignPattern_Singleton ;
Singleton *p = Singleton::Instance() ;
......
}
(2)有子類的情況
方法一:
namespace DesignPattern_Singleton
{
// class Singleton
class Singleton
{
protected:
Singleton() {}
static Singleton *_instance ;
private:
Singleton(const Singleton&) ;
Singleton& operator=(const Singleton&) ;
} ;
Singleton* Singleton::_instance = NULL ;
// class ConcreteSingleton
class ConcreteSingleton : public Singleton
{
public:
static Singleton* Instance() ;
protected:
ConcreteSingleton() {}
} ;
Singleton* ConcreteSingleton::Instance()
{
(_instance == NULL) ? _instance = new ConcreteSingleton() : 0 ;
return _instance ;
}
}
客戶端代碼:
{
using namespace DesignPattern_Singleton ;
Singleton *p = ConcreteSingleton::Instance() ;
}
方法二:
namespace DesignPattern_Singleton
{
// class Singleton
class Singleton
{
protected:
Singleton() {}
private:
Singleton(const Singleton&) ;
Singleton& operator=(const Singleton&) ;
} ;
// class ConcreteSingleton
class ConcreteSingleton : public Singleton
{
public:
static Singleton* Instance() { static ConcreteSingleton _instance ; return &_instance ; }
protected:
ConcreteSingleton() {}
} ;
}
客戶端代碼:
{
using namespace DesignPattern_Singleton ;
Singleton *p = ConcreteSingleton::Instance() ;
}
方法三:
namespace DesignPattern_Singleton
{
template < class T >
class Singleton
{
public:
static T* Instance() { static T _instance ; return &_instance ; }
protected:
Singleton() {}
private:
Singleton(const Singleton &) ;
Singleton& operator=(const Singleton&) ;
} ;
class ConcreteSingleton : public Singleton< ConcreteSingleton > {} ;
}
客戶端代碼
{
using namespace DesignPattern_Singleton ;
ConcreteSingleton *p = ConcreteSingleton::Instance() ;
}
C++模式開發(fā)之Bridge |
|
2002-07-29· · ··COM集中營
|
一、功能 將抽象部分與它的實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地變化。
二、結(jié)構(gòu)圖

|
三、示例代碼
namespace DesignPattern_Bridge
{
// class Implementor
class Implementor
{
public:
virtual void OperationImp() = 0 ;
} ;
// class ConcreteImplementorA
class ConcreteImplementorA : public Implementor
{
public:
virtual void OperationImp() {}
} ;
// class ConcreteImplementorB
class ConcreteImplementorB : public Implementor
{
public:
virtual void OperationImp() {}
} ;
// class Abstraction
class Abstraction
{
public:
void Operation(Implementor* imp) { assert(imp) ; imp->OperationImp() ; }
} ;
}
客戶端代碼:
{
using namespace DesignPattern_Bridge ;
Abstraction obj ;
Implementor *impa = new ConcreteImplementorA() ;
Implementor *impb = new ConcreteImplementorB() ;
obj.Operation(impa) ; //第一種實(shí)現(xiàn)方法
obj.Operation(impb) ; //第二種實(shí)現(xiàn)方法
}
四、實(shí)例
(1)創(chuàng)建可以在X Window System和IBM的Presentation Manager系統(tǒng)中都可以使用的窗口。(書上的例子)

Bridge的魅力在于抽象和實(shí)現(xiàn)之間是松散的關(guān)系,它們之間可以進(jìn)行隨意組合。如上圖中,就有IconWindow+XWindowImp、TransientWindow+XWindowImp、IconWindow+PMWindowImp、TransientWindow+PMWindowImp四種組合。
C++模式設(shè)計(jì)之Builder |
|
2002-07-30· · ··COM集中營
|
一、功能
將一個(gè)復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
二、結(jié)構(gòu)圖
 各類之間的交互關(guān)系如下圖所示:

|
三、示例代碼
namespace DesignPattern_Builder
{
class Product1 { /*...*/ } ;
class Product2 { /*...*/ } ;
// class Builder
class Builder //抽象基類
{
public:
virtual void BuilderPartA() {} //提供缺省實(shí)現(xiàn)
virtual void BuilderPartB() {}
virtual void BuilderPartC() {}
protected:
Builder() {}
} ;
// class ConcreteBuilder1
class ConcreteBuilder1 : public Builder //創(chuàng)建Product1
{
public:
ConcreteBuilder1() : _product(NULL) {}
virtual void BuilderPartA() { /*...*/ }
virtual void BuilderPartB() { /*...*/ }
virtual void BuilderPartC() { /*...*/ }
virtual Product1* GetProduct1() { return _product ; } //返回創(chuàng)建的Product1對象
private:
Product1 *_product ;
} ;
// class ConcreteBuilder2
class ConcreteBuilder2 : public Builder //創(chuàng)建Product2
{
public:
ConcreteBuilder2() : _product(NULL) {}
virtual void BuilderPartA() { /*...*/ }
virtual void BuilderPartB() { /*...*/ }
virtual void BuilderPartC() { /*...*/ }
virtual Product2* GetProduct2() { return _product ; } //返回創(chuàng)建的Product2對象
private:
Product2 *_product ;
} ;
// class Director
class Director
{
public:
//創(chuàng)建對象(Director并不知道具體創(chuàng)建出來的對象是什么樣的,只有調(diào)用該函數(shù)的client知道)
void Construct(Builder *builder)
{
builder->BuilderPartA() ;
builder->BuilderPartB() ;
builder->BuilderPartC() ;
}
} ;
}
客戶端代碼:
{
using namespace DesignPattern_Builder ;
Director director ;
// 創(chuàng)建第一種對象
ConcreteBuilder1 *pBuilder1 = new ConcreteBuilder1() ;
director.Construct(pBuilder1) ;
Product1 *product1 = pBuilder1->GetProduct1() ;
// 創(chuàng)建第二種對象
ConcreteBuilder2 *pBuilder2 = new ConcreteBuilder2() ;
director.Construct(pBuilder2) ;
Product2 *product2 = pBuilder2->GetProduct2() ;
}
四、實(shí)例
(1)例子一。如下圖所示:

上圖的功能是是把一個(gè)RTF文件轉(zhuǎn)換為多種正文格式。RTFReader進(jìn)行語法分析,然后將所有的token串逐一轉(zhuǎn)換??梢奲uilder就是一步步地把各個(gè)部分組裝為一個(gè)整體。它封閉了組裝的方法,組裝出來的對象也大相徑庭。
C++設(shè)計(jì)模式之Prototype |
|
2002-08-01· · ··COM集中營
|
一、功能
用原型實(shí)例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象。
二、結(jié)構(gòu)圖

|
三、優(yōu)缺點(diǎn)
優(yōu)點(diǎn):復(fù)制自身??蛻舨恢佬枰獙ο蟮膶?shí)際類型,只需知道它的抽象基類即可。(即有繼承樹的情況)
缺點(diǎn):必須先有一個(gè)對象實(shí)例(即原型)才能clone。
四、示例代碼
namespace DesignPattern_Prototype
{
// class Prototype
class Prototype //抽象基類
{
public:
virtual Prototype* Clone() = 0 ;
} ;
// class ConcretePrototype1
class ConcretePrototype1 : public Prototype
{
public:
virtual Prototype* Clone()
{
ConcretePrototype1 *p = new ConcretePrototype1() ;
*p = *this ; //復(fù)制對象
return p ;
}
} ;
// class ConcretePrototype2
class ConcretePrototype2 : public Prototype
{
public:
virtual Prototype* Clone()
{
ConcretePrototype2 *p = new ConcretePrototype2() ;
*p = *this ; //復(fù)制對象
return p ;
}
} ;
}
客戶端代碼:
{
using namespace DesignPattern_Prototype ;
ConcretePrototype1 *obj1 = new ConcretePrototype1() ;//原型對象1
ConcretePrototype2 *obj2 = new ConcretePrototype2() ;//原型對象2
Prototype *newobj1 = obj1->Clone() ;//克隆對象1
Prototype *newobj2 = obj2->Clone() ;//克隆對象2
//使用復(fù)制出的對象newobj1和newobj2
}
五、實(shí)例
在一個(gè)圖形編輯器中,每一個(gè)圖形元素,如線、圓、文字等都應(yīng)該支持拷貝操作,即點(diǎn)中圖形,按下Ctrl+C,再按下Ctrl+V后就會復(fù)制一個(gè)新的圖形。顯然這是一種clone操作。所以在每個(gè)從Graphic派生出的圖形子類都應(yīng)運(yùn)用Prototype模式,加上Clone操作。
C++設(shè)計(jì)模式之Factory Method |
|
2002-08-05· · ··COM集中營
|
一、功能
定義一個(gè)用于創(chuàng)建對象的接口,讓子類決定實(shí)例化哪一個(gè)類。Factory Method 使一個(gè)類的實(shí)例化延遲到其子類。
二、結(jié)構(gòu)圖

|
三、實(shí)現(xiàn)
(1)在某些情況下,比如僅僅為了創(chuàng)建適當(dāng)?shù)腜roduct對象而派生新的Creator子類,并且創(chuàng)建不同Product的方法一致時(shí),可以考慮用模板代替繼承。如:
class Creator
{
public:
virtual Product* CreateProduct() = 0 ;
};
template < class ConcreteProduct >
class ConcreteCreator: public Creator
{
public:
virtual Product* CreateProduct() { return new ConcreteProduct() ; }
};
模板與繼承的本質(zhì)區(qū)別之一是:模板:行為不依賴于類型。繼承:行為依賴于類型。(Effective C++ Item 41) 事實(shí)上,在很多模式中都存在著可以用模板代替繼承的情況,其根本原因就在于子類的行為是一致的。
四、示例代碼
namespace DesignPattern_FactoryMethod
{
class Product { /*...*/ } ;
class ConcreteProduct : public Product { /*...*/ } ;
// class Creator
class Creator
{
public:
virtual Product* CreateProduct() = 0 ;
void Operate() ;
} ;
void Creator::Operate()
{
// ...
Product *p = CreateProduct() ;
// ...
}
// class ConcreteCreator
class ConcreteCreator : public Creator
{
public:
virtual Product* CreateProduct() { return new ConcreteProduct() ; }
} ;
}
客戶端代碼:
{
using namespace DesignPattern_FactoryMethod ;
ConcreteCreator p ;
p.Operate() ;
}
這里的CreateProduct其實(shí)也是一個(gè)Template Method。
五、實(shí)例
Factory Method的運(yùn)用太廣泛了,它經(jīng)常運(yùn)用在其它模式中,其實(shí)例舉不勝數(shù)。
(1)

MFC中的CDocument類就包含了類似于上圖CApplication中的三個(gè)函數(shù)。這里的CreateDocument就是一個(gè)factory method,因?yàn)樗?fù)責(zé)創(chuàng)建一個(gè)文檔對象。
(2)

當(dāng)一個(gè)類將它的一些職責(zé)委托給一個(gè)獨(dú)立的類時(shí),就產(chǎn)生了
平行類層次。上圖中Figure和Manipulator就是平行類層次,F(xiàn)igure代表一些圖形元素,如線、文字等,Manipulator表示作用于這些圖形元素的操作,如拖拉、移動、選中等。如果這些操作所需要的狀態(tài)信息并不需要保存在Figure中,那么把Figure和Manipulator分成兩個(gè)類層次是個(gè)好主意。這里的
CreateManipulator就是一個(gè)factory method。
C++設(shè)計(jì)模式之Composite |
|
2002-08-06· · ··COM集中營
|
一、功能 表示“部分-整體”關(guān)系,并使用戶以一致的方式使用單個(gè)對象和組合對象。
二、結(jié)構(gòu)圖

|
上圖中,也可以做些擴(kuò)展,根據(jù)需要可以將Leaf和Composite做為抽象基類,從中派生出子類來。
三、優(yōu)缺點(diǎn)
優(yōu)點(diǎn):對于Composite模式,也許人們一開始的注意力會集中在它是如何實(shí)現(xiàn)組合對象的。但Composite最重要之處在于用戶并不關(guān)心是組合對象還是單個(gè)對象,用戶將以統(tǒng)一的方式進(jìn)行處理,所以基類應(yīng)是從單個(gè)對象和組合對象中提出的公共接口。
缺點(diǎn):Composite最大的問題在于不容易限制組合中的組件。
四、實(shí)現(xiàn)
有時(shí)需要限制組合中的組件,即希望一個(gè)Composite只能有某些特定的Leaf。這個(gè)問題我是用多繼承和動態(tài)類型轉(zhuǎn)換來解決的。假如組合對象Composite1只能包含單個(gè)對象ConcreteLeaf1,Composite2可以包含單個(gè)對象ConcreteLeaf1和ConcreteLeaf2。如下圖所示:

上圖中的類層次比較多,使用了AbstractLeaf1和AbstractLeaf2,但沒使用AbstractComposite1和AbstractComposite2,這個(gè)并不重要,也可以把AbstractLeaf1和AbstractLeaf2去掉,這個(gè)并不重要,可以根據(jù)具體情況決定要不要。
簡單的代碼實(shí)現(xiàn)如下:
namespace DesignPattern_Composite
{
class Component
{
public:
virtual void operation() = 0 ;
virtual void Add(Component*) {}
} ;
class AbstractComponent1 : virtual public Component {} ;
class AbstractLeaf1 : virtual public AbstractComponent1 {} ;
class Composite1 : public AbstractComponent1
{
public:
virtual void operation() { /* do operation */ }
virtual void Add(Component*) ;
} ;
void Composite1::Add(Component *p)
{
AbstractComponent1 *pc1 = dynamic_cast<ABSTRACTCOMPONENT1*>(p) ;
if (pc1 == NULL) return ;
// do add operation
}
class AbstractComponent2 : virtual public Component {} ;
class AbstractLeaf2 : virtual public AbstractComponent2 {} ;
class Composite2 : public AbstractComponent2
{
public:
virtual void operation() { /* do operation */ }
virtual void Add(Component*) ;
} ;
void Composite2::Add(Component *p)
{
AbstractComponent2 *pc2 = dynamic_cast<ABSTRACTCOMPONENT2*>(p) ;
if (pc2 == NULL) return ;
// do add operation
}
class ConcreteLeaf1 : public AbstractLeaf1
{
public:
virtual void operation() { /* do operation */ }
} ;
class ConcreteLeaf2 : public AbstractLeaf1, public AbstractLeaf2
{
public:
virtual void operation() { /* do operation */ }
} ;
}
客戶端代碼:
{
using namespace DesignPattern_Composite ;
Component *pc1 = new ConcreteLeaf1() ;
Component *pc2 = new ConcreteLeaf2() ;
Component *pc3 = new Composite1() ;
Component *pc4 = new Composite2() ;
pc3->Add(pc1) ; // ok
pc3->Add(pc2) ; // ok
pc3->Add(pc3) ; // ok
pc3->Add(pc4) ; // fail
pc4->Add(pc1) ; // fail
pc4->Add(pc2) ; // ok
pc4->Add(pc3) ; // fail
pc4->Add(pc4) ; // ok
}
有兩點(diǎn)需要注意,一是因?yàn)橛昧硕嗬^承,所以需要使用virtual inheritance。二是要用dynamic_cast來判斷是否允許組合該組件。
五、示例代碼
namespace DesignPattern_Composite
{
// class Component
class Component
{
public:
virtual void Operation() = 0 ;
virtual void Add(Component*) {}
} ;
// class Leaf
class Leaf : public Component
{
public:
virtual void Operation() {}
} ;
// class Composite
class Composite : public Component
{
public:
virtual void Add(Component *p) { _list.push_back(p) ; }
virtual void Operation()
{
vector< Component* >::const_iterator it ;
for (it = _list.begin(); it != _list.end(); it++)
(*it)->Operation() ;
}
private:
vector< Component* > _list ;
} ;
}
六、實(shí)例
(1)JUnit中就用的是Composite模式。
