现在的位置: 首页 > 综合 > 正文

c++ 设计模式

2013年02月26日 ⁄ 综合 ⁄ 共 8553字 ⁄ 字号 评论关闭

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

一、功能

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

二、结构图

类厂最基本的结构示意图如下:

在实际应用中,类厂模式可以扩充到很复杂的情况,如下图所示:

三、优缺点

优点:(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

一、功能

保证一个类仅有一个实例。

二、结构图

三、优缺点

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

一、功能

将抽象部分与它的实现部分分离,使它们都可以独立地变化。

抱歉!评论已关闭.