需要应用Adaptor模式的场合通常类似于这样:已有一套或数套遗留系统,需要改造以适它用;或者某组件的设计工序滞后于其使用者,需要重新设计一套新的接口以配接后者……总而言之,该模式作为接口型模式中的首当其冲者,往往与接口的适配联系紧密。
Adaptor模式有两种实现方式:类适配与对象适配。以下给出两种实现的类图:
从上面的结构图可以看出,两种实现的区别在于,类层次的适配是以继承为基础的,而对象层次的适配则以聚合为基础。
下面给出一个实例:
原来的系统中,需要跨类传递成员函数指针,下面是解决方案:
这段代码的缺点在于保留了全局的函数指针,即下句所示:
在尽可能的封装这个意义下考虑上述问题,提出以下重构方案:
下面给出上述代码的设计结构图:
对于函数指针,在STL中的作法是functor,而在.NET中的作法是委托。委托是一种全新的对象类型,其优势在于可指代多个函数指针,从而使得调用方灵活设计稳健的回调式解决方案。
Adaptor模式有两种实现方式:类适配与对象适配。以下给出两种实现的类图:
![](http://www.best4c.com/Best4cUserFiles/20080508/17143_1210181258064.jpg)
![](http://www.best4c.com/Best4cUserFiles/20080508/17143_1210181533689.jpg)
从上面的结构图可以看出,两种实现的区别在于,类层次的适配是以继承为基础的,而对象层次的适配则以聚合为基础。
下面给出一个实例:
原来的系统中,需要跨类传递成员函数指针,下面是解决方案:
#include
<
iostream
>
using namespace std;
class CLobbyClient;
class FUNCTION_CALL
{
typedef int (CLobbyClient:: * RenderFun)( void );
CLobbyClient * it;
RenderFun fun;
public :
FUNCTION_CALL(CLobbyClient * _it, RenderFun _fun)
:it(_it), fun(_fun){}
void operator ()(){(it ->* fun)();}
};
class CGameWindow
{
public :
void MessageLoop(FUNCTION_CALL fun);
};
void CGameWindow::MessageLoop(FUNCTION_CALL fun)
{
fun();
}
class CLobbyClient
{
public :
int Render( void );
};
int CLobbyClient::Render( void )
{
return 1 ;
}
int (CLobbyClient:: * PtrFunc)( void ) = & CLobbyClient::Render;
void main()
{
CGameWindow * wnd = new CGameWindow();
CLobbyClient * lobby = new CLobbyClient();
wnd -> MessageLoop(FUNCTION_CALL(lobby, PtrFunc));
}
using namespace std;
class CLobbyClient;
class FUNCTION_CALL
{
typedef int (CLobbyClient:: * RenderFun)( void );
CLobbyClient * it;
RenderFun fun;
public :
FUNCTION_CALL(CLobbyClient * _it, RenderFun _fun)
:it(_it), fun(_fun){}
void operator ()(){(it ->* fun)();}
};
class CGameWindow
{
public :
void MessageLoop(FUNCTION_CALL fun);
};
void CGameWindow::MessageLoop(FUNCTION_CALL fun)
{
fun();
}
class CLobbyClient
{
public :
int Render( void );
};
int CLobbyClient::Render( void )
{
return 1 ;
}
int (CLobbyClient:: * PtrFunc)( void ) = & CLobbyClient::Render;
void main()
{
CGameWindow * wnd = new CGameWindow();
CLobbyClient * lobby = new CLobbyClient();
wnd -> MessageLoop(FUNCTION_CALL(lobby, PtrFunc));
}
这段代码的缺点在于保留了全局的函数指针,即下句所示:
int
(CLobbyClient::
*
PtrFunc)(
void
)
=
&
CLobbyClient::Render;
在尽可能的封装这个意义下考虑上述问题,提出以下重构方案:
//
增加一个函数对象接口的定义,用来封装全局的函数指针
class RenderFun
{
public :
virtual int operator ()() { return 0 ; }
};
// 增加CClient类的前向声明
class CLobbyClient;
class CGameWindow
{
public :
// 这一句删除,因RenderFun已hook至上述函数对象
// typedef int (*RenderFun)(void);
// 参数改为按引用传递
void MessageLoop(RenderFun & fun);
};
void CGameWindow::MessageLoop(RenderFun & fun)
{
fun();
}
class CLobbyClient : public RenderFun
{
public :
virtual int Render( void );
// 实现()算符
int operator ()() { return Render(); }
};
int CLobbyClient::Render( void )
{
return 1 ;
}
// 这一句删除,事实上它声明了一个全局的函数指针
// int (CLobbyClient::*PtrFunc)(void) = &CLobbyClient::Render;
void main()
{
CGameWindow * wnd = new CGameWindow();
CLobbyClient * lobby = new CLobbyClient();
// 将下面的函数参数作相应改动
wnd -> MessageLoop( * lobby);
}
class RenderFun
{
public :
virtual int operator ()() { return 0 ; }
};
// 增加CClient类的前向声明
class CLobbyClient;
class CGameWindow
{
public :
// 这一句删除,因RenderFun已hook至上述函数对象
// typedef int (*RenderFun)(void);
// 参数改为按引用传递
void MessageLoop(RenderFun & fun);
};
void CGameWindow::MessageLoop(RenderFun & fun)
{
fun();
}
class CLobbyClient : public RenderFun
{
public :
virtual int Render( void );
// 实现()算符
int operator ()() { return Render(); }
};
int CLobbyClient::Render( void )
{
return 1 ;
}
// 这一句删除,事实上它声明了一个全局的函数指针
// int (CLobbyClient::*PtrFunc)(void) = &CLobbyClient::Render;
void main()
{
CGameWindow * wnd = new CGameWindow();
CLobbyClient * lobby = new CLobbyClient();
// 将下面的函数参数作相应改动
wnd -> MessageLoop( * lobby);
}
下面给出上述代码的设计结构图:
![](http://www.best4c.com/Best4cUserFiles/20080508/17143_1210182268751.jpg)
对于函数指针,在STL中的作法是functor,而在.NET中的作法是委托。委托是一种全新的对象类型,其优势在于可指代多个函数指针,从而使得调用方灵活设计稳健的回调式解决方案。