Adapter模式

来自KlniuWiki
跳转到: 导航, 搜索

目录

1 问题

Adapter模式解决的问题在生活中经常会遇到:比如我们有一个Team为外界提供S类服务,但是我们Team里面没有能够完成此项人物的member,然后我们得知有A可以完成这项服务(他把这项人物重新取了个名字叫S’,并且他不对外公布他的具体实现)。为了保证我们对外的服务类别的一致性(提供S服务),我们有以下两种方式解决这个问题:

  1. 把A君直接招安到我们Team为我们工作,提供S服务的时候让A君去办就是了;
  2. A君可能在别的地方有工作,并且不准备接受我们的招安,于是我们Team可以想这样一种方式解决问题:我们安排B君去完成这项任务,并做好工作(Money:))让B君工作的时候可以向A君请教,因此B君就是一个复合体(提供S服务,但是是A君的继承弟子)。

实际上在软件系统设计和开发中,这种问题也会经常遇到:我们为了完成某项工作购买了一个第三方的库来加快开发。这就带来了一个问题:我们在应用程序中已经设计好了接口,与这个第三方提供的接口不一致,为了使得这些接口不兼容的类(不能在一起工作)可以在一起工作了,Adapter模式提供了将一个类(第三方库)的接口转化为客户(购买使用者)希望的接口。

在上面生活中问题的解决方式也就正好对应了Adapter模式的两种类别:类模式和对象模式。

2 功能

将一个类的接口转换成客户希望的另外一个接口,解决两个已有接口之间不匹配的问题。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

3 结构图

  • class adapter

adapter-pattern01.gif

  • object adapter

adapter-pattern02.gif

4 实现

和其他很多模式一样,学习设计模式的重点是学习每种模式的思想,而不应拘泥于它的某种具体结构图和实现。因为模式是灵活的,其实现可以是千变万化的,只是所谓万变不离其宗。在STL中大量运用了Adapter模式,象function adapter、iterator adpter,它们与这里说的adapter结构并不一样,但思想是一样的。具体的介绍可到侯捷网站上找相关文章,他讲得非常好。

5 示例代码

  • 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()
}
  • 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()
}

6 实例

  • 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);
}
  • 近日看了一篇文章“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() ;

上面是示例而非实例,你也许更愿意看看它实际的运用。去下载作者所写的代码,好好欣赏一下吧。

7 参见

个人工具
分类
化学
[×] 國學
学佛
[×] 数学
物理
生活
[×] 英语
读书
辞典
廣告