ADAPTER(适配器)模式

    ADAPTER模式可以将一个类的接口转换成另外一个接口,那样就可以使原来不兼容而不能一起工作的那些类可以一起工作。
    ADAPTER模式也可以称为WRAPPER模式。
    对于ADAPTER模式的简单包装功能,下面以STL中的一个例子来说明: 

//  下列代码片断摘自VC++ 6.0中的STACK
//  可以在..VC98/Include/STACK中找到
template < class  _Ty,  class  _C  =  deque < _Ty >   >
    
class  stack {
public :

    
//  ......

    value_type
&  top()
        {
return  (c.back()); }

    
const  value_type &  top()  const
        {
return  (c.back()); }

    
void  push( const  value_type &  _X)
        {c.push_back(_X); }

    
void  pop()
        {c.pop_back(); }

    
//  ......

protected :
    _C c;
    };

    可以看到stack就是deque的一个简单封装,也可以说stack是deque的一个适配器。通过这种简单的方法,就把deque的方法back(),push_back()和pop_back()给转换成了stack的top(),push()和pop()。
    在上面的代码中只是用到了ADAPTER模式中的对象适配器,还有一种是类适配器。下面我就用一个C++的小例子来说明这两种适配器的区别和优缺点。
    比如我们有一个视图系统,可以显示长方形、正方形和圆形,我们很容易利用COMPOSITE模式做出如下设计:
    (关于COMPOSITE模式可以参考我的《重读《设计模式》之学习笔记(五)--我对COMPOSITE模式的理解》《VISITOR模式--《敏捷软件开发》读书笔记(三)》

class  CShape
{
public :
    
~ CShape() {};

    
virtual   void  Draw()  =   0 ;
};

//  这里以输出一句话来代替具体的draw过程

class  CRectangle :  public  CShape
{
public :
    
void  Draw() { cout  <<   " Draw a rectangle. "   <<  endl; };
};

class  CSquare :  public  CShape
{
public :
    
void  Draw() { cout  <<   " Draw a square. "   <<  endl; };
};

class  CCircle :  public  CShape
{
public :
    
void  Draw() { cout  <<   " Draw a circle. "   <<  endl; };
};

class  CView :  public  CShape
{
public :
    
~ CView()
    {
        
while ( ! m_vShape.empty())
        {
            CShape 
* pShape  =  (CShape * )m_vShape.back();
            m_vShape.pop_back();

            delete pShape;
        }
    }

    
void  Draw()
    {
        cout 
<<   " Draw a view. "   <<  endl;

        
for  (vector < CShape *> ::const_iterator it  =  m_vShape.begin(); it  !=  m_vShape.end();  ++ it)
            (
* it) -> Draw();
    }

    
void  AddShape(CShape  * pShape)
    {
        
if  (pShape)
            m_vShape.push_back(pShape);
    }

private :
    vector
< CShape *>  m_vShape;
};

    我们可以用下面的测试函数检验上面设计的正确性:

void  Test()
{
    CView view;

    CRectangle 
* pRectangle  =   new  CRectangle;
    view.AddShape(pRectangle);

    CSquare 
* pSquare  =   new  CSquare;
    view.AddShape(pSquare);

    CCircle 
* pCircle  =   new  CCircle;
    view.AddShape(pCircle);

    view.Draw();
}

    现在,我们想在我们的这个视图系统里面添加对文本显示的支持。由于文本的显示跟图形的显示有很大差别,我们决定用别人已经开发好的类。比如下面的CText 类:

class  CContext
{
public :
    
~ CContext() {};

    
virtual   void  DrawText()  =   0 ;
};

//  这里也以输出一句话来代替具体的draw过程

class  CText :  public  CContext
{
public :
    
void  DrawText() { cout  <<   " Draw a text. "   <<  endl; };
};

    由于类CText 的父类不是CShape,而且接口跟我们想要的接口不一样。为了在我们的系统中使用类CText 来显示文本,就可以使用ADAPTER模式创建一个类CText 的adapter,使CText 的接口适应我们已经写好的视图系统。
    下面使用的是用类适配器:

class  CShapeText :  public  CShape,  private  CText
{
public :
    
void  Draw() { DrawText(); };

private :
    
void  DrawText()
    {
        CText::DrawText();

        
//  这里可以改变父类的部分行为
        cout  <<   "   It is a text adapter. "   <<  endl;
    }
};

    类CShapeText就是类CText的类适配器,它从类CShape公有继承接口,而从类CText私有继承了实现。这样我们就可以把CShapeText加入到我们已经开发好的视图体统里面了。比如下面这个测试函数:

void  Test()
{
    CView view;

    CRectangle 
* pRectangle  =   new  CRectangle;
    view.AddShape(pRectangle);

    CSquare 
* pSquare  =   new  CSquare;
    view.AddShape(pSquare);

    CCircle 
* pCircle  =   new  CCircle;
    view.AddShape(pCircle);

    
//  在这里CShapeText跟其他CShape的子类一样的使用
    
//  完全融入到已开发好的视图系统中
    CShapeText  * pText  =   new  CShapeText;
    view.AddShape(pText);
    
    view.Draw();
}

    下面用对象适配器来实现相同的功能:

class  CShapeText :  public  CShape
{
public :
    CShapeText(CContext 
* pText) { m_pText  =  pText; };

    
void  Draw() { m_pText -> DrawText(); };

private :
    CContext 
* m_pText;
};

    可以看到,代码中通过一个对象指针来调用相应的方法来实现将接口转换为我们希望得到的接口。下面是一个新的测试函数:

void  Test()
{
    CView view;

    CRectangle 
* pRectangle  =   new  CRectangle;
    view.AddShape(pRectangle);

    CSquare 
* pSquare  =   new  CSquare;
    view.AddShape(pSquare);

    CCircle 
* pCircle  =   new  CCircle;
    view.AddShape(pCircle);

    
//  这里的CShapeText一样可以很好的融入到已开发好的视图系统中
    CText  * pText  =   new  CText;
    CShapeText 
* pShapeText  =   new  CShapeText(pText);
    view.AddShape(pShapeText);

    view.Draw();
}

    通过上面的代码我们可以看出类适配器和对象适配器各自的优缺点:
    类适配器:
    优点:可以重新定义被适配的类的部分行为。
    缺点:不能适配一个类以及它的子类。
    对象适配器:
    优点:可以适配一个类以及它的所有子类。
    缺点:重新定义被适配的类的行为比较困难。
    因此,我们可以得出结论:如果要适配一个类以及它的子类,或者只是简单的包装以转换接口,那就使用对象适配器;其他情况就用类适配器。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值