一、功能
将一個類的接口轉換成客戶希望的另外一個接口,解決兩個已有接口之間不比對的問題。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() ; |