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

c++设计模式(6)-Adapter

2013年06月19日 ⁄ 综合 ⁄ 共 5306字 ⁄ 字号 评论关闭
一、功能

  将一个类的接口转换成客户希望的另外一个接口,解决两个已有接口之间不匹配的问题。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的类定义:

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
};

  关键之处在于_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() ;

抱歉!评论已关闭.