程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> 我的Design Pattern之旅[6]:Adapter Pattern(OO)

我的Design Pattern之旅[6]:Adapter Pattern(OO)

編輯:關於C#

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。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved