在OO設計裡,我們常會定下interface要求其他class必須實現此interface,以便彼此溝通,若是新開發的專案,問題就不大;若既有的framework/library中,已經有符合需求的class,但唯一可惜的是,『可能interface並不相同』,導致無法和我的class合作,此時可使用Adpater Pattern解決。
Abstract
在OO設計裡,我們常會定下interface要求其他class必須實現此interface,以便彼此溝通,若是新開發的專案,問題就不大;若既有的framework/library中,已經有符合需求的class,但唯一可惜的是,『因為interface並不相同』,導致無法和我的class合作,此時可使用Adpater Pattern解決。
Intent
將class的interface轉換成外界所預期的另一種interface,讓原先囿於interface不相容問題而無法協力合作的class能夠兜再一起用[1]。
Introduction
adapter中文為轉換器、轉接器,主要的目的就是將不相容的interface做轉換。現實生活中,處處可以看到adapter,如Notebook內部使用的是DC(直流電),但插頭提供的是AC(交流電),所以必須使用AC to DC adapter將交流電轉換成直流電,Notebook才能使用;又如現在很多Notebook並沒有COM port,取而代之的是USB port,但很多嵌入式系統開發版必須使用COM port才能與PC連接,因此就有USB to COM的adapter,讓Notebook可以和開發版做連接。OO設計也是如此,若interface不相容,則可透過Adapter Pattern解決。
Structure[1]
Class Adapter (使用繼承技術)
Object Adapter (使用組合技術)
Participants[1]
Client
與符合ITarget interface的object合作。
ITarget
定義Client所用的與應用領域相關之interface。
Adaptee
需要被轉換的既有interface。
Adapter
將Adaptee轉換成ITarget interface。
Collaborations
Client呼叫Adapter的method,Adapter再去呼叫Adaptee的method完成任務[1]。
Implementation
Class Adapter
ISO C++ (使用多重繼承,對ITarget使用public繼承,對Adaptee使用private繼承,因為Adaptee僅需Adapter內部使用即可。)
/**//*
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename : DP_AdapterPattern_ClassAdapter_Classic.cpp
Compiler : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to implement Class Adapter Classic.
Release : 07/15/2007 1.0
*/
#include <iostream>
using namespace std;
class ITarget {
public:
virtual void request() const = 0;
};
class Adaptee {
public:
void specificRequest() const;
};
void Adaptee::specificRequest() const {
cout << "Hello Adaptee!!" << endl;
}
class Adapter : public ITarget, private Adaptee {
public:
virtual void request() const;
};
void Adapter::request() const {
specificRequest();
}
int main() {
Adapter adapter;
adapter.request();
}
C#
/**//*
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename : DP_AdapterPattern_ClassAdapter_Classic.cs
Compiler : Visual Studio 2005 / C# 2.0
Description : Demo how to implement Class Adapter Classic.
Release : 07/15/2007 1.0
*/
using System;
interface ITarget {
void request();
}
class Adaptee {
public void specificRequest() {
Console.WriteLine("Hello Adaptee!!");
}
}
class Adapter : Adaptee, ITarget {
public void request() {
specificRequest();
}
}
class Client {
static void Main() {
ITarget adapter = new Adapter();
adapter.request();
}
}
C++/CLI
/**//*
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename : DP_AdapterPattern_ClassAdapter_Classic.cpp
Compiler : Visual C++ 8.0 / C++/CLI
Description : Demo how to implement Class Adapter Classic.
Release : 07/15/2007 1.0
*/
#include "stdafx.h"
using namespace System;
interface class ITarget {
void request();
};
ref class Adaptee {
public:
void specificRequest();
};
void Adaptee::specificRequest() {
Console::WriteLine("Hello Adaptee!!");
}
ref class Adapter : public Adaptee, public ITarget {
public:
virtual void request();
};
void Adapter::request() {
specificRequest();
}
int main() {
ITarget^ adapter = gcnew Adapter();
adapter->request();
}
VB
'
'(C) OOMusou 2007 http://oomusou.cnblogs.com
'Filename : DP_AdapterPattern_ClassAdapter_Classic.vb
'Compiler : VB 9
'Description : Demo how to implement Class Adapter Classic.
'Release : 07/15/2007 1.0
'
Imports System
Interface ITragetInterface ITraget
Sub request()Sub request()
End Interface
Class AdapteeClass Adaptee
Public Sub specificRequest()Sub specificRequest()
Console.WriteLine("Hello Adaptee!!")
End Sub
End Class
Class AdapterClass Adapter
Inherits Adaptee
Implements ITraget
Public Sub request()Sub request() Implements ITraget.request
specificRequest()
End Sub
End Class
Class ClientClass Client
Shared Sub Main()Sub Main()
Dim adapter As ITraget = New Adapter()
adapter.request()
End Sub
End Class
執行結果
Hello Adaptee!!
Object Adapter
ISO C++
/**//*
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename : DP_AdapterPattern_ObjectAdapter_Classic.cpp
Compiler : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to implement Object Adapter Classic.
Release : 07/15/2007 1.0
*/
#include <iostream>
using namespace std;
class ITarget {
public:
virtual void request() const = 0;
};
class Adaptee {
public:
void specificRequest() const;
};
void Adaptee::specificRequest() const {
cout << "Hello Adaptee!!" << endl;
}
class Adapter : public ITarget {
public:
Adapter(Adaptee* adaptee = 0) : _adaptee(adaptee) {}
virtual void request() const;
protected:
Adaptee* _adaptee;
};
void Adapter::request() const {
if (_adaptee)
_adaptee->specificRequest();
}
int main() {
Adapter adapter(&Adaptee());
adapter.request();
}
C#
/**//*
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename : DP_AdapterPattern_ClassAdapter_Object.cs
Compiler : Visual Studio 2005 / C# 2.0
Description : Demo how to implement Class Adapter Object.
Release : 07/15/2007 1.0
*/
using System;
interface ITarget {
void request();
}
class Adaptee {
public void specificRequest() {
Console.WriteLine("Hello Adaptee!!");
}
}
class Adapter : ITarget {
protected Adaptee _adaptee = null;
public Adapter() {}
public Adapter(Adaptee adaptee) {
_adaptee = adaptee;
}
public void request() {
if (_adaptee != null)
_adaptee.specificRequest();
}
}
class Client {
static void Main() {
Adapter adapter = new Adapter(new Adaptee());
adapter.request();
}
}
C++/CLI
/**//*
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename : DP_AdapterPattern_ObjectAdapter_Classic.cpp
Compiler : Visual C++ 8.0 / C++/CLI
Description : Demo how to implement Object Adapter Classic.
Release : 07/15/2007 1.0
*/
#include "stdafx.h"
using namespace System;
interface class ITarget {
void request();
};
ref class Adaptee {
public:
void specificRequest();
};
void Adaptee::specificRequest() {
Console::WriteLine("Hello Adaptee!!");
}
ref class Adapter : public ITarget {
protected:
Adaptee^ _adaptee;
public:
Adapter() : _adaptee(nullptr) {}
Adapter(Adaptee^ adaptee) : _adaptee(adaptee) {}
public:
virtual void request();
};
void Adapter::request() {
if (_adaptee != nullptr)
_adaptee->specificRequest();
}
int main() {
Adapter^ adapter = gcnew Adapter(gcnew Adaptee);
adapter->request();
}
VB
'
'(C) OOMusou 2007 http://oomusou.cnblogs.com
'Filename : DP_AdapterPattern_ObjectAdapter_Classic.vb
'Compiler : VB 9
'Description : Demo how to implement Object Adapter Classic.
'Release : 07/15/2007 1.0
'
Imports System
Interface ITargetInterface ITarget
Sub request()Sub request()
End Interface
Class AdapteeClass Adaptee
Public Sub specificRequest()Sub specificRequest()
Console.WriteLine("Hello Adaptee!!")
End Sub
End Class
Class AdapterClass Adapter
Implements ITarget
Protected _adaptee As Adaptee
Public Sub New()Sub New(Optional ByRef adaptee As Adaptee = Nothing)
_adaptee = adaptee
End Sub
Public Sub request()Sub request() Implements ITarget.request
If _adaptee IsNot Nothing Then
_adaptee.specificRequest()
End If
End Sub
End Class
Class ClientClass Client
Shared Sub Main()Sub Main()
Dim adapter As ITarget = New Adapter(New Adaptee())
adapter.request()
End Sub
End Class
執行結果
Hello Adaptee!!
Consequence
Class Adapter和Object Adapter各有優缺點:
Class Adapter
優點:
1.容易override Adaptee原本的行為。
因為Class Adapter繼承了Adaptee,所以可以輕易的override Adaptee。
2.代碼較精簡。
缺點:
1.只能轉換單一Adaptee。
因為使用繼承技術,所以Class Adapter的內容會綁死在特定的Adaptee的concreate class或derived class身上,因此Class Adapter無法同時轉換多個Adaptee。(若配合泛型技術,可以解掉此問題,請參閱(原創) 我的Design Pattern之旅[7]:使用泛型改進Adapter Pattern (OO) (Design Pattern) (C/C++) (template) (C++/CLI)。
2.無法動態改變欲轉換的Adaptee。
因為使用繼承技術,在compile-time已經決定了要繼承的Adaptee,所以無法動態改變Adaptee。
Object Adapter
優點:
1.可轉換多個Adaptee。
因為使用了組合技術,配合polymorphism(多型/多態),所以能轉換class和其derived class。
2.可動態改變欲轉換的Adaptee。
因為使用了組合技術,可以在run-time的改變欲轉換的Adaptee。
缺點:
1.較難override Adaptee原本的行為。
若需override Adaptee原本的行為,必須先繼承Adaptee之後,override之,然後Adapter再組合Adaptee的driverd class。
2.代碼較多。
Class Adapter和Object Adapter優缺點剛好互補,可依實際需求決定之,大體上而言,Object Adapter優於Class Adapter,因為彈性較大,且可面對將來未知的class,也應證了那句『多用組合,少用繼承』的Design Pattern三句真言。
Example
在(原創) 我的Design Pattern之旅[1]:Strategy Pattern (OO) (Design Pattern) (C?C++) (template) (.NET) (C#)中Grapher使用了Strategy Pattern,為了可動態載入畫Triangle,畫Circle,畫Squre的算法,我們定了IDrawStrategy interface,並且寫了Triangle、Circle、Square三個class實現IDrawStrategy interface,但今天發現在某個framwork/library中(如.NET Framework中的GDI+或DirectX),已經存在畫Triangle、Circle、Square的算法了,所以不需重新自己寫,但因為interface不同,所以Grapher無法使用,且我們又沒有該framework/library的source code,根本無法修改成實現IDrawStrategy interface(如我們根本沒有DirectX或.NET Framework的source code),所以我們只好寫一個DrawAdapter,讓Grapher可以使用之。
Class Adapter
IDrawStrategy interface定的是draw(),但IPaint interface定的是paint(),所以Grapher無法使用,因為無法修改IPaint interface和Triangle class、Circle class、Square class(因為可能在其他Framework內,無source code可修改),所以只好加上TriangleDrawAdapter,CircleDrawAdapter和SquareDrawAdapter做轉換。
ISO C++
/**//*
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename : DP_AdpaterPattern_Strategy_Class.cpp
Compiler : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to use Strategy Pattern with Adapter Pattern (Class).
Release : 07/15/2007 1.0
*/
#include <iostream>
using namespace std;
class IDrawStrategy {
public:
virtual void draw() const = 0;
};
class Grapher {
public:
Grapher(IDrawStrategy* drawStrategy = 0) : _drawStrategy(drawStrategy) {}
public:
void drawShape() const;
void setShape(IDrawStrategy* drawStrategy);
protected:
IDrawStrategy* _drawStrategy;
};
void Grapher::drawShape() const {
if (_drawStrategy)
_drawStrategy->draw();
}
void Grapher::setShape(IDrawStrategy* drawStrategy) {
_drawStrategy = drawStrategy;
}
class IPaint {
public:
virtual void paint() const = 0;
};
class Triangle : public IPaint {
public:
void paint() const;
};
void Triangle::paint() const {
cout << "Draw Triangle" << endl;
}
class Circle : public IPaint {
public:
void paint() const;
};
void Circle::paint() const {
cout << "Draw Circle" << endl;
}
class Square : public IPaint {
public:
void paint() const;
};
void Square::paint() const {
cout << "Draw Square" << endl;
}
class TriangleDrawAdapter : public IDrawStrategy, private Triangle {
public:
virtual void draw() const;
};
void TriangleDrawAdapter::draw() const {
paint();
}
class CircleDrawAdapter : public IDrawStrategy, private Circle {
public:
virtual void draw() const;
};
void CircleDrawAdapter::draw() const {
paint();
}
class SquareDrawAdapter : public IDrawStrategy, private Square {
public:
virtual void draw() const;
};
void SquareDrawAdapter::draw() const {
paint();
}
int main() {
Grapher grapher(&TriangleDrawAdapter());
grapher.drawShape();
grapher.setShape(&CircleDrawAdapter());
grapher.drawShape();
grapher.setShape(&SquareDrawAdapter());
grapher.drawShape();
}
C#
/**//*
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename : DP_AdpaterPattern_Strategy_Class.cs
Compiler : Visual Studio 2005 / C# 2.0
Description : Demo how to use Strategy Pattern with Adapter Pattern (Class)
Release : 07/11/2007 1.0
*/
using System;
interface IDrawStrategy {
void draw();
}
class Grapher {
protected IDrawStrategy _drawStrategy = null;
public Grapher() {}
public Grapher(IDrawStrategy drawStrategy) {
_drawStrategy = drawStrategy;
}
public void drawShape() {
if (_drawStrategy != null)
_drawStrategy.draw();
}
public void setShape(IDrawStrategy drawStrategy) {
_drawStrategy = drawStrategy;
}
}
interface IPaint {
void paint();
}
class Triangle : IPaint {
public void paint() {
Console.WriteLine("Draw Triangle");
}
}
class Circle : IPaint {
public void paint() {
Console.WriteLine("Draw Circle");
}
}
class Square : IPaint {
public void paint() {
Console.WriteLine("Draw Square");
}
}
class TriangleDrawAdapter : Triangle, IDrawStrategy {
public void draw() {
paint();
}
}
class CircleDrawAdapter : Circle, IDrawStrategy {
public void draw() {
paint();
}
}
class SquareDrawAdapter : Square, IDrawStrategy {
public void draw() {
paint();
}
}
class Client {
static void Main() {
Grapher grapher = new Grapher(new TriangleDrawAdapter());
grapher.drawShape();
grapher.setShape(new CircleDrawAdapter());
grapher.drawShape();
grapher.setShape(new SquareDrawAdapter());
grapher.drawShape();
}
}
C++/CLI
/**//*
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename : DP_AdpaterPattern_Strategy_Class.cpp
Compiler : Visual C++ 8.0 / C++/CLI
Description : Demo how to use Strategy Pattern with Adapter Pattern (Class)
Release : 07/12/2007 1.0
*/
#include "stdafx.h"
using namespace System;
interface class IDrawStrategy {
void draw();
};
ref class Grapher {
public:
Grapher() : _drawStrategy(nullptr) {}
Grapher(IDrawStrategy^ drawStrategy) : _drawStrategy(drawStrategy) {}
public:
void drawShape();
void setShape(IDrawStrategy^ drawStrategy);
protected:
IDrawStrategy^ _drawStrategy;
};
void Grapher::drawShape() {
if (_drawStrategy != nullptr)
_drawStrategy->draw();
}
void Grapher::setShape(IDrawStrategy^ drawStrategy) {
_drawStrategy = drawStrategy;
}
interface class IPaint {
void paint();
};
ref class Triangle : public IPaint {
public:
virtual void paint();
};
void Triangle::paint() {
Console::WriteLine("Draw Triangle");
}
ref class Circle : public IPaint {
public:
virtual void paint();
};
void Circle::paint() {
Console::WriteLine("Draw Circle");
}
ref class Square : public IPaint {
public:
virtual void paint();
};
void Square::paint() {
Console::WriteLine("Draw Square");
}
ref class TriangleDrawAdapter : public IDrawStrategy, public Triangle {
public:
virtual void draw();
};
void TriangleDrawAdapter::draw() {
paint();
}
ref class CircleDrawAdapter : public IDrawStrategy, public Circle {
public:
virtual void draw();
};
void CircleDrawAdapter::draw() {
paint();
}
ref class SquareDrawAdapter : public IDrawStrategy, public Square {
public:
virtual void draw();
};
void SquareDrawAdapter::draw() {
paint();
}
int main() {
Grapher^ grapher = gcnew Grapher(gcnew TriangleDrawAdapter);
grapher->drawShape();
grapher->setShape(gcnew CircleDrawAdapter);
grapher->drawShape();
grapher->setShape(gcnew SquareDrawAdapter);
grapher->drawShape();
}
VB
'
'(C) OOMusou 2007 http://oomusou.cnblogs.com
'Filename : DP_AdpaterPattern_Strategy_Class.vb
'Compiler : VB 9
'Description : Demo how to use Strategy Pattern with Adapter Pattern (Class)
'Release : 07/12/2007 1.0
'
Imports System
Interface IDrawStrategyInterface IDrawStrategy
Sub draw()Sub draw()
End Interface
Class GrapherClass Grapher
Protected _drawStrategy As IDrawStrategy
Public Sub New()Sub New(Optional ByRef drawStrategy As IDrawStrategy = Nothing)
_drawStrategy = drawStrategy
End Sub
Public Sub drawShape()Sub drawShape()
If _drawStrategy IsNot Nothing Then
_drawStrategy.draw()
End If
End Sub
Public Sub setShape()Sub setShape(ByRef drawStrategy As IDrawStrategy)
_drawStrategy = drawStrategy
End Sub
End Class
Interface IPaintInterface IPaint
Sub paint()Sub paint()
End Interface
Class TriangleClass Triangle
Implements IPaint
Public Sub paint()Sub paint() Implements IPaint.paint
Console.WriteLine("Draw Triangle")
End Sub
End Class
Class CircleClass Circle
Implements IPaint
Public Sub paint()Sub paint() Implements IPaint.paint
Console.WriteLine("Draw Circle")
End Sub
End Class
Class SquareClass Square
Implements IPaint
Public Sub paint()Sub paint() Implements IPaint.paint
Console.WriteLine("Draw Square")
End Sub
End Class
Class TriangleDrawAdapterClass TriangleDrawAdapter
Inherits Triangle
Implements IDrawStrategy
Public Sub draw()Sub draw() Implements IDrawStrategy.draw
Me.paint()
End Sub
End Class
Class CircleDrawAdapterClass CircleDrawAdapter
Inherits Circle
Implements IDrawStrategy
Public Sub draw()Sub draw() Implements IDrawStrategy.draw
Me.paint()
End Sub
End Class
Class SquareDrawAdapterClass SquareDrawAdapter
Inherits Square
Implements IDrawStrategy
Public Sub draw()Sub draw() Implements IDrawStrategy.draw
Me.paint()
End Sub
End Class
Class ClientClass Client
Shared Sub Main()Sub Main()
Dim grapher As Grapher = New Grapher(New TriangleDrawAdapter())
grapher.drawShape()
grapher.setShape(New CircleDrawAdapter())
grapher.drawShape()
grapher.setShape(New SquareDrawAdapter())
grapher.drawShape()
End Sub
End Class
執行結果
Draw Triangle
Draw Circle
Draw Square
Class Adapter的缺點在此範例很明顯,因為使用繼承技術,所以每個Class需要有相對應的Adapter,使用泛型可以稍微解決此問題,不過僅能使用ISO C++和C++/CLI的template來解決,C#、C++/CLI、VB的Generics都無福消受,請參閱 (原創) 我的Design Pattern之旅[7]:使用泛型改進Adapter Pattern (OO) (Design Pattern) (C/C++) (template) (C++/CLI)。
Object Adapter
ISO C++
/**//*
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename : DP_AdpaterPattern_Strategy_Object.cpp
Compiler : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to use Strategy Pattern with Adapter Pattern (Object)
Release : 07/11/2007 1.0
*/
#include <iostream>
using namespace std;
class IDrawStrategy {
public:
virtual void draw() const = 0;
};
class Grapher {
public:
Grapher(IDrawStrategy* drawStrategy = 0) : _drawStrategy(drawStrategy) {}
public:
void drawShape() const;
void setShape(IDrawStrategy* drawStrategy);
protected:
IDrawStrategy* _drawStrategy;
};
void Grapher::drawShape() const {
if (_drawStrategy)
_drawStrategy->draw();
}
void Grapher::setShape(IDrawStrategy* drawStrategy) {
_drawStrategy = drawStrategy;
}
class IPaint {
public:
virtual void paint() const = 0;
};
class Triangle : public IPaint {
public:
void paint() const;
};
void Triangle::paint() const {
cout << "Draw Triangle" << endl;
}
class Circle : public IPaint {
public:
void paint() const;
};
void Circle::paint() const {
cout << "Draw Circle" << endl;
}
class Square : public IPaint {
public:
void paint() const;
};
void Square::paint() const {
cout << "Draw Square" << endl;
}
class DrawAdapter : public IDrawStrategy {
public:
DrawAdapter(IPaint* adaptee = 0) : _adaptee(adaptee) {}
virtual void draw() const;
protected:
IPaint* _adaptee;
};
void DrawAdapter::draw() const {
_adaptee->paint();
}
int main() {
Grapher grapher(&DrawAdapter(&Triangle()));
grapher.drawShape();
grapher.setShape(&DrawAdapter(&Circle()));
grapher.drawShape();
grapher.setShape(&DrawAdapter(&Square()));
grapher.drawShape();
}
C#
/**//*
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename : DP_AdpaterPattern_Strategy_Object.cs
Compiler : Visual Studio 2005 / Visual C# 2.0
Description : Demo how to use Strategy Pattern with Adapter Pattern (Object)
Release : 07/11/2007 1.0
*/
using System;
interface IDrawStrategy {
void draw();
}
class Grapher {
protected IDrawStrategy _drawStrategy = null;
public Grapher() {}
public Grapher(IDrawStrategy drawStrategy) {
_drawStrategy = drawStrategy;
}
public void drawShape() {
if (_drawStrategy != null)
_drawStrategy.draw();
}
public void setShape(IDrawStrategy drawStrategy) {
_drawStrategy = drawStrategy;
}
};
interface IPaint {
void paint();
}
class Triangle : IPaint {
public void paint() {
Console.WriteLine("Draw Triangle");
}
}
class Circle : IPaint {
public void paint() {
Console.WriteLine("Draw Circle");
}
}
class Square : IPaint {
public void paint() {
Console.WriteLine("Draw Square");
}
};
class DrawAdapter : IDrawStrategy {
protected IPaint _adaptee = null;
public DrawAdapter() {}
public DrawAdapter(IPaint adaptee) {
_adaptee = adaptee;
}
public void draw() {
_adaptee.paint();
}
}
class Client {
static void Main() {
Grapher grapher = new Grapher(new DrawAdapter(new Triangle()));
grapher.drawShape();
grapher.setShape(new DrawAdapter(new Circle()));
grapher.drawShape();
grapher.setShape(new DrawAdapter(new Square()));
grapher.drawShape();
}
}
C++/CLI
/**//*
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename : DP_AdpaterPattern_Strategy_Object.cpp
Compiler : Visual C++ 8.0 / C++/CLI
Description : Demo how to use Strategy Pattern with Adpater Pattern (Object)
Release : 07/12/2007 1.0
*/
#include "stdafx.h"
using namespace System;
interface class IDrawStrategy {
void draw();
};
ref class Grapher {
public:
Grapher() : _drawStrategy(nullptr) {}
Grapher(IDrawStrategy^ drawStrategy) : _drawStrategy(drawStrategy) {}
public:
void drawShape();
void setShape(IDrawStrategy^ drawStrategy);
protected:
IDrawStrategy^ _drawStrategy;
};
void Grapher::drawShape() {
if (_drawStrategy != nullptr)
_drawStrategy->draw();
}
void Grapher::setShape(IDrawStrategy^ drawStrategy) {
_drawStrategy = drawStrategy;
}
interface class IPaint {
void paint();
};
ref class Triangle : public IPaint {
public:
virtual void paint();
};
void Triangle::paint() {
Console::WriteLine("Draw Triangle");
}
ref class Circle : public IPaint {
public:
virtual void paint();
};
void Circle::paint() {
Console::WriteLine("Draw Circle");
}
ref class Square : public IPaint {
public:
virtual void paint();
};
void Square::paint() {
Console::WriteLine("Draw Square");
}
ref class DrawAdapter : public IDrawStrategy {
public:
DrawAdapter() : _adaptee(nullptr) {}
DrawAdapter(IPaint^ adaptee) : _adaptee(adaptee) {}
virtual void draw();
protected:
IPaint^ _adaptee;
};
void DrawAdapter::draw() {
_adaptee->paint();
}
int main() {
Grapher^ grapher = gcnew Grapher(gcnew DrawAdapter(gcnew Triangle));
grapher->drawShape();
grapher->setShape(gcnew DrawAdapter(gcnew Circle));
grapher->drawShape();
grapher->setShape(gcnew DrawAdapter(gcnew Square));
grapher->drawShape();
}
VB
'
'(C) OOMusou 2007 http://oomusou.cnblogs.com
'Filename : DP_AdpaterPattern_Strategy_Class.vb
'Compiler : VB 9
'Description : Demo how to use Strategy Pattern with Adapter Pattern (Class)
'Release : 07/12/2007 1.0
'
Imports System
Interface IDrawStrategyInterface IDrawStrategy
Sub draw()Sub draw()
End Interface
Class GrapherClass Grapher
Protected _drawStrategy As IDrawStrategy
Public Sub New()Sub New(Optional ByRef drawStrategy As IDrawStrategy = Nothing)
_drawStrategy = drawStrategy
End Sub
Public Sub drawShape()Sub drawShape()
If _drawStrategy IsNot Nothing Then
_drawStrategy.draw()
End If
End Sub
Public Sub setShape()Sub setShape(ByRef drawStrategy As IDrawStrategy)
_drawStrategy = drawStrategy
End Sub
End Class
Interface IPaintInterface IPaint
Sub paint()Sub paint()
End Interface
Class TriangleClass Triangle
Implements IPaint
Public Sub paint()Sub paint() Implements IPaint.paint
Console.WriteLine("Draw Triangle")
End Sub
End Class
Class CircleClass Circle
Implements IPaint
Public Sub paint()Sub paint() Implements IPaint.paint
Console.WriteLine("Draw Circle")
End Sub
End Class
Class SquareClass Square
Implements IPaint
Public Sub paint()Sub paint() Implements IPaint.paint
Console.WriteLine("Draw Square")
End Sub
End Class
Class TriangleDrawAdapterClass TriangleDrawAdapter
Inherits Triangle
Implements IDrawStrategy
Public Sub draw()Sub draw() Implements IDrawStrategy.draw
Me.paint()
End Sub
End Class
Class CircleDrawAdapterClass CircleDrawAdapter
Inherits Circle
Implements IDrawStrategy
Public Sub draw()Sub draw() Implements IDrawStrategy.draw
Me.paint()
End Sub
End Class
Class SquareDrawAdapterClass SquareDrawAdapter
Inherits Square
Implements IDrawStrategy
Public Sub draw()Sub draw() Implements IDrawStrategy.draw
Me.paint()
End Sub
End Class
Class ClientClass Client
Shared Sub Main()Sub Main()
Dim grapher As Grapher = New Grapher(New TriangleDrawAdapter())
grapher.drawShape()
grapher.setShape(New CircleDrawAdapter())
grapher.drawShape()
grapher.setShape(New SquareDrawAdapter())
grapher.drawShape()
End Sub
End Class
執行結果
Draw Triangle
Draw Circle
Draw Square
Object Adapter的優點在此範例可以明顯看出,只需一個DrawAdapter就可轉換所有class,未來若有新的class,也不需再修改DrawAdapter,符合OCP原則,且又可動態載入不同的Adaptee。
Conclusion
Design Pattern的修為重在了解class間該如何布局以解決問題,但坊間講Design Pattern的書大都用C++或Java,C#很少,VB更少,本文同時用了ISO C++、C#、C++/CLI、VB來實現Adapter Pattern,各位讀者可依自己的需要,選擇自己喜歡的語言來了解Adapter Pattern。
See Also
(原創) 我的Design Pattern之旅[1]:Strategy Pattern (OO) (Design Pattern) (C?C++) (template) (.NET) (C#)
(原創) 我的Design Pattern之旅[7]:使用泛型改進Adapter Pattern (OO) (Design Pattern) (C/C++) (template) (C++/CLI)
Reference
[1] Gof, Design Patterns,Addison Weseley Longman,1995