C++設計模式(轉載)

C++設計模式之Adapter 一、功能   將一個類的接口轉換成客戶希望的另外一個接口,解決兩個已有接口之間不匹配的問題。Adapter模式使得原本由於接口不兼容而不能一起工作的那些類可以一起工作。

  二、結構圖

(1)class adapter

  (2)object adapter

     三、實現

和其他很多模式一樣,學習設計模式的重點是學習每種模式的思 想,而不應拘泥於它的某種具體結構圖和實現。因爲模式是靈活的,其實現可以是千變萬化的,只是所謂萬變不離其宗。 在STL中大量運用了Adapter模式,象function adapter、iterator adpter,它們與這裏說的adapter結構並不一樣,但思想是一樣的。具體的介紹可到侯捷網站上找相關文章,他講得非常好。

  四、示例代碼

(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() ; //實際上調用的是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() ; //實際上調用的是Adaptee::SpecialRequest() }

  六、實例

(1)STL中的Class Adapter   STL中的Adapter Class包括:a.stack(對應的adaptee是deque)。b.queue(對應的adaptee是deque)。 c.priority_queue(對應的adaptee是vector)。 下面是從VC中的< stack >拷出的stack的類定義:

template class _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 };

  關鍵之處在於_Container c,stack所有的操作都轉交給c去處理了。(這實際上就是前面所說的"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模式,也有一定代表性。我將其問題一般化,概括出以下示例:

  問題:假設有幾個已有類,他們有某些共同的行爲,但它們彼此間是獨立的(沒有共同的基類)。如:

class T1 { public: void Proc() {} } ;

class T2 { public: void Proc() {} } ;

// ...

  如何以統一的方式去調用這些行爲呢?

  解決方法1:很自然的會想到用模板,如:

template <class T> void Test(T t) { t.Proc() ; }

  的確不錯,但這隻適用於簡單的情況,有時情況是很複雜的,比如我們無法把類型放到模板參數中!

  解決方法2:困難來自於這些類沒有共同的基類,所以我們就創造一個基類,然後再Adapt。

// class IAdaptor,抽象基類 class IAdaptor { public: virtual void Proc() = 0 ; } ; // class Adaptor template <class T> class Adaptor : public IAdaptor, private T //實現繼承 { public: virtual void Proc() { T::Proc() ; } } ; // 以統一方式調用函數Proc,而不關心是T1、T2或其他什麼類 void Test(const std::auto_ptr& sp) { sp->Proc() ; } 客戶端代碼: Test(std::auto_ptr(new Adaptor)) ; Test(std::auto_ptr(new Adaptor)) ;

  上例很簡單,用方法一中的模板函數就可以很好地解決了。下面是一個略微複雜一點的例子,根據參數類型來創建適當的對象:

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 //實現繼承 { 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() ;

上面是示例而非實例,你也許更願意看看它實際的運用。去下載作者所寫的代碼,好好欣賞一下吧。
C++設計模式之Abstract Factory
2002-07-23· · ··COM集中營
  一、功能   提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類。

  二、結構圖

類廠最基本的結構示意圖如下:

  在實際應用中,類廠模式可以擴充到很複雜的情況,如下圖所示:

  三、優缺點

  優點:(1)封裝創建過程。客戶不用知道類廠是如何創建類實例的,類廠封閉了所有創建的細節。這樣可選擇不同的創建方法,增加了靈活性。 (2)將客戶與具體類隔離,提高了各自的可重用性。   缺點:Factory類層次與具體類層次通常是平行的(即一一對應的)。增加一個具體類,一般也要相應地增加一個factory類,增加了系統複雜度。

  四、實現

(1)Abstract Factory類中通常是一組Factory Method的集合。個人認爲與Factory Method模式沒有本質區別。   (2)通常可以把工廠作爲單件。

  五、示例代碼

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 ;// 創建ProductA     virtual AbstractProductB* CreateProductB() = 0 ;// 創建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 ;   // 第一種創建方法   AbstractFactory *pFactory = ConcreteFactory1::Instance() ;   AbstractProductA *pProductA = pFactory->CreateProductA() ;   AbstractProductB *pProductB = pFactory->CreateProductB() ;   // 第二種創建方法   pFactory = ConcreteFactory2::Instance() ;   pProductA = pFactory->CreateProductA() ;   pProductB = pFactory->CreateProductB() ; }

  六、實例

最早知道類廠的概念是在COM中,但當時也沒想到這是如此重要的一種模式,在許多其他模式中都可以用到類廠模式。 COM中不能直接創建組件,這也是由COM的一個特性決定的:即客戶不知道要創建的組件的類名。
C++設計模式之Singleton
2002-07-26· · ··COM集中營
  一、功能

  保證一個類僅有一個實例。   二、結構圖

  三、優缺點

  Singleton模式是做爲"全局變量"的替代品出現的。所以它具有全局變量的特點:全局可見、貫穿應用程序的整個生命期,它也具有全局變量不具備的性質:同類型的對象實例只可能有一個。

  四、實現

  教科書上的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)因爲返回的是指針,爲防止用戶調用delete函數,可把static Singleton *_instance;改爲在Instance()中定義static Singleton _instance。這樣顯然更安全,同時也具有lazy initialization的特性(即第一次訪問時才創建)。   (2)假設需要從Singleton派生子類,而子類也需要有同 樣的性質,既只能創建一個實例。我覺得,這很難辦。根本原因在於Instance()函數不是虛函數,不具有多態的性質。一種常用方法是把 Instance()函數移到子類中,這時就只能用static Singleton *_instance,而不能用static Singleton _instance了,除非把_instance也要移到子類,無論怎麼做都不優雅。另一種方法是用模板。具體用什麼方法,只能根據實際情況權衡。   五、示例代碼

  (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++模式開發之Bridge
2002-07-29· · ··COM集中營
  一、功能   將抽象部分與它的實現部分分離,使它們都可以獨立地變化。

  二、結構圖

、示例代碼

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) ; //第一種實現方法 obj.Operation(impb) ; //第二種實現方法 }

  四、實例

(1)創建可以在X Window System和IBM的Presentation Manager系統中都可以使用的窗口。(書上的例子)

  Bridge的魅力在於抽象和實現之間是鬆散的關係,它們之間可以進行隨意組合。如上圖中,就有IconWindow+ XWindowImp、TransientWindow+XWindowImp、IconWindow+PMWindowImp、 TransientWindow+PMWindowImp四種組合。

C++模式設計之Builder
2002-07-30· · ··COM集中營
  一、功能   將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示

  二、結構圖

  各類之間的交互關係如下圖所示:

三、示例代碼

namespace DesignPattern_Builder { class Product1 { /*...*/ } ; class Product2 { /*...*/ } ;

// class Builder class Builder //抽象基類 { public: virtual void BuilderPartA() {} //提供缺省實現 virtual void BuilderPartB() {} virtual void BuilderPartC() {} protected: Builder() {} } ;

// class ConcreteBuilder1 class ConcreteBuilder1 : public Builder //創建Product1 { public: ConcreteBuilder1() : _product(NULL) {}

virtual void BuilderPartA() { /*...*/ } virtual void BuilderPartB() { /*...*/ } virtual void BuilderPartC() { /*...*/ }

virtual Product1* GetProduct1() { return _product ; } //返回創建的Product1對象 private: Product1 *_product ; } ;

// class ConcreteBuilder2 class ConcreteBuilder2 : public Builder //創建Product2 { public: ConcreteBuilder2() : _product(NULL) {}

virtual void BuilderPartA() { /*...*/ } virtual void BuilderPartB() { /*...*/ } virtual void BuilderPartC() { /*...*/ }

virtual Product2* GetProduct2() { return _product ; } //返回創建的Product2對象 private: Product2 *_product ; } ;

// class Director class Director { public: //創建對象(Director並不知道具體創建出來的對象是什麼樣的,只有調用該函數的client知道) void Construct(Builder *builder) { builder->BuilderPartA() ; builder->BuilderPartB() ; builder->BuilderPartC() ; } } ; }

客戶端代碼: { using namespace DesignPattern_Builder ;

Director director ;

// 創建第一種對象 ConcreteBuilder1 *pBuilder1 = new ConcreteBuilder1() ; director.Construct(pBuilder1) ; Product1 *product1 = pBuilder1->GetProduct1() ;

// 創建第二種對象 ConcreteBuilder2 *pBuilder2 = new ConcreteBuilder2() ; director.Construct(pBuilder2) ; Product2 *product2 = pBuilder2->GetProduct2() ; }

  四、實例

  (1)例子一。如下圖所示:

  上圖的功能是是把一個RTF文件轉換爲多種正文格式。RTFReader進行語法分析,然後將所有的token串逐一轉換。可見builder就是一步步地把各個部分組裝爲一個整體。它封閉了組裝的方法,組裝出來的對象也大相徑庭。

C++設計模式之Prototype
2002-08-01· · ··COM集中營
  一、功能

  用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。

  二、結構圖

  三、優缺點

  優點:複製自身。客戶不知道需要對象的實際類型,只需知道它的抽象基類即可。(即有繼承樹的情況)   缺點:必須先有一個對象實例(即原型)才能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 ; //複製對象 return p ; } } ;

// class ConcretePrototype2 class ConcretePrototype2 : public Prototype { public: virtual Prototype* Clone() { ConcretePrototype2 *p = new ConcretePrototype2() ; *p = *this ; //複製對象 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

//使用複製出的對象newobj1和newobj2 }

  五、實例

     在一個圖形編輯器中,每一個圖形元素,如線、圓、文字等都應該支持拷貝操作,即點中圖形,按下Ctrl+C,再按下Ctrl+V後就會複製一個新的圖形。顯然這是一種clone操作。所以在每個從Graphic派生出的圖形子類都應運用Prototype模式,加上Clone操作。

C++設計模式之Factory Method
2002-08-05· · ··COM集中營
  一、功能

  定義一個用於創建對象的接口,讓子類決定實例化哪一個類。Factory Method 使一個類的實例化延遲到其子類。

  二、結構圖

  三、實現

(1)在某些情況下,比如僅僅爲了創建適當的Product對象而派生新的Creator子類,並且創建不同Product的方法一致時,可以考慮用模板代替繼承。如:
class Creator { public: virtual Product* CreateProduct() = 0 ; }; template < class ConcreteProduct > class ConcreteCreator: public Creator { public: virtual Product* CreateProduct() { return new ConcreteProduct() ; } };

    模板與繼承的本質區別之一是:模板:行爲不依賴於類型。繼承:行爲依賴於類型。(Effective C++ Item 41) 事實上,在很多模式中都存在着可以用模板代替繼承的情況,其根本原因就在於子類的行爲是一致的

  四、示例代碼

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其實也是一個Template Method。

  五、實例

  Factory Method的運用太廣泛了,它經常運用在其它模式中,其實例舉不勝數。 (1)

  MFC中的CDocument類就包含了類似於上圖CApplication中的三個函數。這裏的CreateDocument就是一個factory method,因爲它負責創建一個文檔對象。

  (2)

  當一個類將它的一些職責委託給一個獨立的類時,就產生了平行類層次。上圖中Figure和Manipulator就是平 行類層次,Figure代表一些圖形元素,如線、文字等,Manipulator表示作用於這些圖形元素的操作,如拖拉、移動、選中等。如果這些操作所需 要的狀態信息並不需要保存在Figure中,那麼把Figure和Manipulator分成兩個類層次是個好主意。這裏的CreateManipulator就是一個factory method。

C++設計模式之Composite
2002-08-06· · ··COM集中營
  一、功能   表示“部分-整體”關係,並使用戶以一致的方式使用單個對象和組合對象。

  二、結構圖

  上圖中,也可以做些擴展,根據需要可以將Leaf和Composite做爲抽象基類,從中派生出子類來。

  三、優缺點

  優點:對於Composite模式,也許人們一開始的注意力會集中在它是如何實現組合對象的。但Composite最重要之處在於用戶並不關心是組合對象還是單個對象,用戶將以統一的方式進行處理,所以基類應是從單個對象和組合對象中提出的公共接口。   缺點:Composite最大的問題在於不容易限制組合中的組件。

  四、實現

有時需要限制組合中的組件,即希望一個Composite只能有某些特定的Leaf。這個問題我是 用多繼承和動態類型轉換來解決的。假如組合對象Composite1只能包含單個對象ConcreteLeaf1,Composite2可以包含單個對象 ConcreteLeaf1和ConcreteLeaf2。如下圖所示:

  上圖中的類層次比較多,使用了AbstractLeaf1和AbstractLeaf2,但沒使用 AbstractComposite1和AbstractComposite2,這個並不重要,也可以把AbstractLeaf1和 AbstractLeaf2去掉,這個並不重要,可以根據具體情況決定要不要。 簡單的代碼實現如下:

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 }

  有兩點需要注意,一是因爲用了多繼承,所以需要使用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 ; } ; }

  六、實例

  (1)JUnit中就用的是Composite模式。

發佈了0 篇原創文章 · 獲贊 4 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章