(原創) 我的Design Pattern之旅[7]:使用泛型改進Adapter Pattern (OO) (Design Pattern) (C/C++) (template) (.NET) (C#...

Abstract
Adapter Pattern有Class Adapter和Object Adapter兩種實現方式。Class Adapter的優點是可override Adaptee,且實現方式較簡單,但缺點是只能針對特定class量身訂做Adapter,配合泛型,可解決Class Adapter的缺點。

Introduction
(原創) 我的Design Pattern之旅[6] : Adapter Pattern (OO) (Design Pattern) (C/C++) (.NET) (C#) (C++/CLI) (VB) 中的Grapher範例,我們看到Class Adapter必須針對Triangle、Circle、Square量身訂做TriangleDrawAdapter、CircleDrawAdapter、SquareDrawAdapter,雖然符合OCP,但每個class就得需要專屬的Adapter,會造成class爆炸,本文試著用泛型來解決此問題。


ISO C++

ContractedBlock.gif ExpandedBlockStart.gif
ExpandedBlockStart.gifContractedBlock.gif/**//* 
InBlock.gif(C) OOMusou 2007 
http://oomusou.cnblogs.com
InBlock.gif
InBlock.gifFilename    : DP_AdpaterPattern_Strategy_ClassByTemplate.cpp
InBlock.gifCompiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
InBlock.gifDescription : Demo how to use Strategy Pattern with Adpater Pattern (Class Adapter) By Template
InBlock.gifRelease     : 07/11/2007 1.0
ExpandedBlockEnd.gif
*/

None.gif#include 
<iostream>
None.gif
using namespace std;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
class IDrawStrategy dot.gif{
InBlock.gif
public:
InBlock.gif  
virtual void draw() const = 0;
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
class Grapher dot.gif{
InBlock.gif
public:
ExpandedSubBlockStart.gifContractedSubBlock.gif  Grapher(IDrawStrategy
* drawStrategy = 0) : _drawStrategy(drawStrategy) dot.gif{}
InBlock.gif  
InBlock.gif
public:
InBlock.gif  
void drawShape() const;
InBlock.gif  
void setShape(IDrawStrategy* drawStrategy);
InBlock.gif  
InBlock.gif
protected:
InBlock.gif  IDrawStrategy
* _drawStrategy;
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Grapher::drawShape() const dot.gif{
InBlock.gif  
if (_drawStrategy)
InBlock.gif      _drawStrategy
->draw();
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Grapher::setShape(IDrawStrategy* drawStrategy) dot.gif{
InBlock.gif  _drawStrategy 
= drawStrategy;
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
class IPaint dot.gif{
InBlock.gif
public:
InBlock.gif  
virtual void paint() const = 0;
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
class Triangle : public IPaint dot.gif{
InBlock.gif
public:
InBlock.gif  
void paint() const;
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Triangle::paint() const dot.gif{
InBlock.gif  cout 
<< "Draw Triangle" << endl;
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
class Circle : public IPaint dot.gif{
InBlock.gif
public:
InBlock.gif  
void paint() const;
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Circle::paint() const dot.gif{
InBlock.gif  cout 
<< "Draw Circle" << endl;
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
class Square : public IPaint dot.gif{
InBlock.gif
public:
InBlock.gif  
void paint() const;
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Square::paint() const dot.gif{
InBlock.gif  cout 
<< "Draw Square" << endl;
ExpandedBlockEnd.gif}

None.gif
None.giftemplate
<typename T>
ExpandedBlockStart.gifContractedBlock.gif
class DrawAdapter : public IDrawStrategy, private T dot.gif{
InBlock.gif
public:
InBlock.gif  
virtual void draw() const;  
ExpandedBlockEnd.gif}
;
None.gif
None.giftemplate
<typename T>
ExpandedBlockStart.gifContractedBlock.gif
void DrawAdapter<T>::draw() const dot.gif{
InBlock.gif  paint();
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
int main() dot.gif{
InBlock.gif  Grapher grapher(
&DrawAdapter<Triangle>());
InBlock.gif  grapher.drawShape();
InBlock.gif  
InBlock.gif  grapher.setShape(
&DrawAdapter<Circle>());
InBlock.gif  grapher.drawShape();
InBlock.gif  
InBlock.gif  grapher.setShape(
&DrawAdapter<Square>());
InBlock.gif  grapher.drawShape();
ExpandedBlockEnd.gif}


執行結果

None.gif Draw Triangle
None.gifDraw Circle
None.gifDraw Square


從UML可以發現,TriangleDrawAdapter、CircleDrawAdapter和SquareDrawAdapter都不見了,只剩下一個DrawAdapter,為什麼可以這樣子呢?因為Class Adapter的致命傷就是得繼承Adaptee,這是很強的coupling,利用泛型,我們將繼承的class變成泛型的參數
70行

None.gif template < typename T >
ExpandedBlockStart.gifContractedBlock.gif
class  DrawAdapter :  public  IDrawStrategy,  private  T  dot.gif {
InBlock.gif
public:
InBlock.gif  
virtual void draw() const;  
ExpandedBlockEnd.gif}
;


這樣就可以在Client動態的以Adaptee為泛型參數傳入Class Adapter

ExpandedBlockStart.gif ContractedBlock.gif int  main()  dot.gif {
InBlock.gif  Grapher grapher(
&DrawAdapter<Triangle>());
InBlock.gif  grapher.drawShape();
InBlock.gif  
InBlock.gif  grapher.setShape(
&DrawAdapter<Circle>());
InBlock.gif  grapher.drawShape();
InBlock.gif  
InBlock.gif  grapher.setShape(
&DrawAdapter<Square>());
InBlock.gif  grapher.drawShape();
ExpandedBlockEnd.gif}


C++/CLI

ContractedBlock.gif ExpandedBlockStart.gif
ExpandedBlockStart.gifContractedBlock.gif/**//* 
InBlock.gif(C) OOMusou 2007 
http://oomusou.cnblogs.com
InBlock.gif
InBlock.gifFilename    : DP_AdpaterPattern_Strategy_ClassByTemplate.cpp
InBlock.gifCompiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
InBlock.gifDescription : Demo how to use Strategy Pattern with Adpater Pattern (Class Adapter) By Template
InBlock.gifRelease     : 07/12/2007 1.0
ExpandedBlockEnd.gif
*/
None.gif#include 
"stdafx.h"
None.gif
using namespace System;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
interface class IDrawStrategy dot.gif{
InBlock.gif  
void draw();
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
ref class Grapher dot.gif{
InBlock.gif
public:
ExpandedSubBlockStart.gifContractedSubBlock.gif  Grapher() : _drawStrategy(nullptr) 
dot.gif{}
ExpandedSubBlockStart.gifContractedSubBlock.gif  Grapher(IDrawStrategy
^ drawStrategy) : _drawStrategy(drawStrategy) dot.gif{}
InBlock.gif  
InBlock.gif
public:
InBlock.gif  
void drawShape();
InBlock.gif  
void setShape(IDrawStrategy^ drawStrategy);
InBlock.gif  
InBlock.gif
protected:
InBlock.gif  IDrawStrategy
^ _drawStrategy;
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Grapher::drawShape() dot.gif{
InBlock.gif  
if (_drawStrategy != nullptr)
InBlock.gif      _drawStrategy
->draw();
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Grapher::setShape(IDrawStrategy^ drawStrategy) dot.gif{
InBlock.gif  _drawStrategy 
= drawStrategy;
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
interface class IPaint dot.gif{
InBlock.gif  
void paint();
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
ref class Triangle : public IPaint dot.gif{
InBlock.gif
public:
InBlock.gif  
virtual void paint();
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Triangle::paint() dot.gif{
InBlock.gif  Console::WriteLine(
"Draw Triangle");
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
ref class Circle : public IPaint dot.gif{
InBlock.gif
public:
InBlock.gif  
virtual void paint();
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Circle::paint() dot.gif{
InBlock.gif  Console::WriteLine(
"Draw Circle");
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
ref class Square : public IPaint dot.gif{
InBlock.gif
public:
InBlock.gif  
virtual void paint();
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Square::paint() dot.gif{
InBlock.gif  Console::WriteLine(
"Draw Square");
ExpandedBlockEnd.gif}

None.gif
None.giftemplate
<typename T>
ExpandedBlockStart.gifContractedBlock.gif
ref class DrawAdapter : public IDrawStrategy, public T dot.gif{
InBlock.gif
public:
InBlock.gif  
virtual void draw();  
ExpandedBlockEnd.gif}
;
None.gif
None.giftemplate
<typename T>
ExpandedBlockStart.gifContractedBlock.gif
void DrawAdapter<T>::draw() dot.gif{
InBlock.gif  paint();
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
int main() dot.gif{
InBlock.gif  Grapher
^ grapher = gcnew Grapher(gcnew DrawAdapter<Triangle>);
InBlock.gif  grapher
->drawShape();
InBlock.gif  
InBlock.gif  grapher
->setShape(gcnew DrawAdapter<Circle>);
InBlock.gif  grapher
->drawShape();
InBlock.gif  
InBlock.gif  grapher
->setShape(gcnew DrawAdapter<Square>);
InBlock.gif  grapher
->drawShape();
ExpandedBlockEnd.gif}


執行結果

None.gif Draw Triangle
None.gifDraw Circle
None.gifDraw Square


在.NET語言內,C++/CLI是唯一得天獨厚有兩種泛型的語言,C++/CLI可以用ISO C++既有的template,也可以用CLI的Generics。有了template,C++/CLI也可以實現這個技巧。


69行

None.gif template < typename T >
ExpandedBlockStart.gifContractedBlock.gif
ref   class  DrawAdapter :  public  IDrawStrategy,  public  T  dot.gif {
InBlock.gif
public:
InBlock.gif  
virtual void draw();  
ExpandedBlockEnd.gif}
;


80行

ExpandedBlockStart.gifContractedBlock.gif int  main()  dot.gif {
InBlock.gif  Grapher
^ grapher = gcnew Grapher(gcnew DrawAdapter<Triangle>);
InBlock.gif  grapher
->drawShape();
InBlock.gif  
InBlock.gif  grapher
->setShape(gcnew DrawAdapter<Circle>);
InBlock.gif  grapher
->drawShape();
InBlock.gif  
InBlock.gif  grapher
->setShape(gcnew DrawAdapter<Square>);
InBlock.gif  grapher
->drawShape();
ExpandedBlockEnd.gif}


C++/CLI也可以在Client動態改變泛型參數來改善Class Adapter。

看到這裡,你或許會問,C#可以嗎?既然C# 2.0也有泛型,答案很遺憾,目前C# 2.0不行,C# 3.0我還沒試,或許有興趣的朋友可以試看看。


C#

ContractedBlock.gif ExpandedBlockStart.gif
ExpandedBlockStart.gifContractedBlock.gif/**//* 
InBlock.gif(C) OOMusou 2007 
http://oomusou.cnblogs.com
InBlock.gif
InBlock.gifFilename    : DP_AdpaterPattern_Strategy_ClassByTemplate_Error.cs
InBlock.gifCompiler    : Visual Studio 2005 / C# 2.0
InBlock.gifDescription : Demo how to use Strategy Pattern with Adpater Pattern (Class Adapter) By Template
InBlock.gifRelease     : 07/11/2007 1.0
ExpandedBlockEnd.gif
*/

None.gif
using System;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
interface IDrawStrategy dot.gif{
InBlock.gif  
void draw();
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
class Grapher dot.gif{
InBlock.gif  
protected IDrawStrategy _drawStrategy;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public Grapher() dot.gif{ }
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public Grapher(IDrawStrategy drawStrategy) dot.gif{
InBlock.gif    _drawStrategy 
= drawStrategy;
ExpandedSubBlockEnd.gif  }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void drawShape() dot.gif{
InBlock.gif    
if (_drawStrategy != null)
InBlock.gif      _drawStrategy.draw();
ExpandedSubBlockEnd.gif  }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void setShape(IDrawStrategy drawStrategy) dot.gif{
InBlock.gif    _drawStrategy 
= drawStrategy;
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
interface IPaint dot.gif{
InBlock.gif  
void paint();
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
class Triangle : IPaint dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void paint() dot.gif{
InBlock.gif    Console.WriteLine(
"Draw Triangle");
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
class Circle : IPaint dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void paint() dot.gif{
InBlock.gif    Console.WriteLine(
"Draw Circle");
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
class Square : IPaint dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void paint() dot.gif{
InBlock.gif    Console.WriteLine(
"Draw Square");
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
None.gif
// Error : Cannot derive from 'T' because it is a type parameter
ExpandedBlockStart.gifContractedBlock.gif
class DrawAdapter<T> : IDrawStrategy, T dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void draw() dot.gif{
InBlock.gif    paint();
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
class Client dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif  
static void Main() dot.gif{
InBlock.gif    Grapher grapher 
= new Grapher(new DrawAdapter<Triangle>());
InBlock.gif    grapher.drawShape();
InBlock.gif
InBlock.gif    grapher.setShape(
new DrawAdapter<Circle>());
InBlock.gif    grapher.drawShape();
InBlock.gif
InBlock.gif    grapher.setShape(
new DrawAdapter<Square>());
InBlock.gif    grapher.drawShape();
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}


以上C#無法compile成功,錯在55行

None.gif //  Error : Cannot derive from 'T' because it is a type parameter
ExpandedBlockStart.gifContractedBlock.gif
class  DrawAdapter < T >  : IDrawStrategy, T  dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void draw() dot.gif{
InBlock.gif    paint();
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}


錯誤訊息為

None.gif Error : Cannot derive from 'T' because it is a type parameter


也就是說,C#不允許繼承泛型,CLI的語言C#、VB、C++/CLI的Generics都無法用這個技巧,但C#卻可用『組合泛型』的方式完成。

C# by Generics

ContractedBlock.gif ExpandedBlockStart.gif
ExpandedBlockStart.gifContractedBlock.gif/**//* 
InBlock.gif(C) OOMusou 2007 
http://oomusou.cnblogs.com
InBlock.gif
InBlock.gifFilename    : DP_AdpaterPattern_Strategy_ClassByGenerics.cs
InBlock.gifCompiler    : Visual Studio 2005 / C# 2.0
InBlock.gifDescription : Demo how to use Strategy Pattern with Adpater Pattern (Class Adapter) By Template
InBlock.gifRelease     : 07/11/2007 1.0
ExpandedBlockEnd.gif
*/

None.gif
using System;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
interface IDrawStrategy dot.gif{
InBlock.gif  
void draw();
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
class Grapher dot.gif{
InBlock.gif  
protected IDrawStrategy _drawStrategy;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public Grapher() dot.gif{ }
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public Grapher(IDrawStrategy drawStrategy) dot.gif{
InBlock.gif    _drawStrategy 
= drawStrategy;
ExpandedSubBlockEnd.gif  }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void drawShape() dot.gif{
InBlock.gif    
if (_drawStrategy != null)
InBlock.gif      _drawStrategy.draw();
ExpandedSubBlockEnd.gif  }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void setShape(IDrawStrategy drawStrategy) dot.gif{
InBlock.gif    _drawStrategy 
= drawStrategy;
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
interface IPaint dot.gif{
InBlock.gif  
void paint();
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
class Triangle : IPaint dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void paint() dot.gif{
InBlock.gif    Console.WriteLine(
"Draw Triangle");
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
class Circle : IPaint dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void paint() dot.gif{
InBlock.gif    Console.WriteLine(
"Draw Circle");
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
class Square : IPaint dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void paint() dot.gif{
InBlock.gif    Console.WriteLine(
"Draw Square");
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
class DrawAdapter<T> : IDrawStrategy where T : IPaint, new() dot.gif{
InBlock.gif  
protected T _adaptee = new T();
InBlock.gif  
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void draw() dot.gif{
InBlock.gif    _adaptee.paint();
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
class Client dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif  
static void Main() dot.gif{
InBlock.gif    Grapher grapher 
= new Grapher(new DrawAdapter<Triangle>());
InBlock.gif    grapher.drawShape();
InBlock.gif
InBlock.gif    grapher.setShape(
new DrawAdapter<Circle>());
InBlock.gif    grapher.drawShape();
InBlock.gif
InBlock.gif    grapher.setShape(
new DrawAdapter<Square>());
InBlock.gif    grapher.drawShape();
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}


執行結果

None.gif Draw Triangle
None.gifDraw Circle
None.gifDraw Square


55行

ExpandedBlockStart.gif ContractedBlock.gif class  DrawAdapter < T >  : IDrawStrategy where T : IPaint,  new ()  dot.gif {
InBlock.gif  
protected T _adaptee = new T();
InBlock.gif  
ExpandedSubBlockStart.gifContractedSubBlock.gif  
public void draw() dot.gif{
InBlock.gif    _adaptee.paint();
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}


C#若要使用泛型的method,就得加上constraint,又因為使用delegation的方式,所以必須將泛型new起來,C#規定要在constraint加上new()。

C++/CLI by Generics

ContractedBlock.gif ExpandedBlockStart.gif
ExpandedBlockStart.gifContractedBlock.gif/**//* 
InBlock.gif(C) OOMusou 2007 
http://oomusou.cnblogs.com
InBlock.gif
InBlock.gifFilename    : DP_AdpaterPattern_Strategy_ClassByGenerics.cs
InBlock.gifCompiler    : Visual Studio 2005 / C++/CLI
InBlock.gifDescription : Demo how to use Strategy Pattern with Adpater Pattern (Class Adapter) By Generics
InBlock.gifRelease     : 07/20/2007 1.0
ExpandedBlockEnd.gif
*/

None.gif
None.gif#include 
"stdafx.h"
None.gif
None.gif
using namespace System;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
interface class IDrawStrategy dot.gif{
InBlock.gif  
void draw();
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
ref class Grapher dot.gif{
InBlock.gif
public
ExpandedSubBlockStart.gifContractedSubBlock.gif  Grapher() 
dot.gif{}
ExpandedSubBlockStart.gifContractedSubBlock.gif  Grapher(IDrawStrategy
^ drawStrategy) : _drawStrategy(drawStrategy) dot.gif{}
InBlock.gif
InBlock.gif
public
InBlock.gif  
void drawShape();
InBlock.gif  
void setShape(IDrawStrategy^ drawStrategy);
InBlock.gif  
InBlock.gif
protected:
InBlock.gif  IDrawStrategy
^ _drawStrategy;
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Grapher::drawShape() dot.gif{
InBlock.gif  
if (_drawStrategy != nullptr)
InBlock.gif    _drawStrategy
->draw();
ExpandedBlockEnd.gif}

None.gif
None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Grapher::setShape(IDrawStrategy^ drawStrategy) dot.gif{
InBlock.gif  _drawStrategy 
= drawStrategy;
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
interface class IPaint dot.gif{
InBlock.gif  
void paint();
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
ref class Triangle : public IPaint dot.gif{
InBlock.gif
public
InBlock.gif  
virtual void paint();
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Triangle::paint() dot.gif{
InBlock.gif  Console::WriteLine(
"Draw Triangle");
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
ref class Circle : public IPaint dot.gif{
InBlock.gif
public
InBlock.gif  
virtual void paint();
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Circle::paint() dot.gif{
InBlock.gif  Console::WriteLine(
"Draw Circle");
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
ref class Square : public IPaint dot.gif{
InBlock.gif
public
InBlock.gif  
virtual void paint();
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
void Square::paint() dot.gif{
InBlock.gif  Console::WriteLine(
"Draw Square");
ExpandedBlockEnd.gif}

None.gif
None.gifgeneric
<typename T>
None.gifwhere T : IPaint, gcnew()
ExpandedBlockStart.gifContractedBlock.gif
ref class DrawAdapter : public IDrawStrategy  dot.gif{
InBlock.gif
public:
ExpandedSubBlockStart.gifContractedSubBlock.gif  DrawAdapter() : _adaptee(gcnew T)
dot.gif{}
InBlock.gif
public:
InBlock.gif  
virtual void draw();
InBlock.gif  
InBlock.gif
protected:
InBlock.gif  T _adaptee;
ExpandedBlockEnd.gif}
;
None.gif
None.gifgeneric
<typename T>
ExpandedBlockStart.gifContractedBlock.gif
void DrawAdapter<T>::draw() dot.gif{
InBlock.gif  _adaptee
->paint();
ExpandedBlockEnd.gif}

None.gif
None.gif
ExpandedBlockStart.gifContractedBlock.gif 
int main() dot.gif{
InBlock.gif  Grapher
^ grapher = gcnew Grapher(gcnew DrawAdapter<Triangle^>);
InBlock.gif  grapher
->drawShape();
InBlock.gif
InBlock.gif  grapher
->setShape(gcnew DrawAdapter<Circle^>);
InBlock.gif  grapher
->drawShape();
InBlock.gif
InBlock.gif  grapher
->setShape(gcnew DrawAdapter<Square^>);
InBlock.gif  grapher
->drawShape();
ExpandedBlockEnd.gif}


執行結果

None.gif Draw Triangle
None.gifDraw Circle
None.gifDraw Square


72行

None.gif generic < typename T >
None.gifwhere T : IPaint, gcnew()
ExpandedBlockStart.gifContractedBlock.gif
ref   class  DrawAdapter :  public  IDrawStrategy   dot.gif {
InBlock.gif
public:
ExpandedSubBlockStart.gifContractedSubBlock.gif  DrawAdapter() : _adaptee(gcnew T)
dot.gif{}
InBlock.gif
public:
InBlock.gif  
virtual void draw();
InBlock.gif  
InBlock.gif
protected:
InBlock.gif  T _adaptee;
ExpandedBlockEnd.gif}
;


C++/CLI的Generics寫法和C#類似,不過又不完全一樣。

VB by Generics

ContractedBlock.gif ExpandedBlockStart.gif
None.gif' 
None.gif'
(C) OOMusou 2007 http://oomusou.cnblogs.com
None.gif'
None.gif'
Filename    : DP_AdpaterPattern_Strategy_ClassByGenerics.vb
None.gif'
Compiler    : Visual Studio 2005 / VB 9
None.gif'
Description : Demo how to use Strategy Pattern with Adpater Pattern (Class Adapter) By Generics
None.gif'
Release     : 07/20/2007 1.0
None.gif'
None.gif

None.gif
Imports System
None.gif
ExpandedBlockStart.gifContractedBlock.gif
Interface IDrawStrategyInterface IDrawStrategy
ExpandedSubBlockStart.gifContractedSubBlock.gif  
Sub draw()Sub draw()
ExpandedBlockEnd.gif
End Interface

None.gif
ExpandedBlockStart.gifContractedBlock.gif
Class GrapherClass Grapher
InBlock.gif  
Protected _drawStrategy As IDrawStrategy
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
Public Sub New()Sub New(Optional ByRef drawStrategy As IDrawStrategy = Nothing)
InBlock.gif    _drawStrategy 
= drawStrategy
ExpandedSubBlockEnd.gif  
End Sub

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
Public Sub drawShape()Sub drawShape()
InBlock.gif    
If (_drawStrategy IsNot NothingThen
InBlock.gif      _drawStrategy.draw()
InBlock.gif    
End If
ExpandedSubBlockEnd.gif  
End Sub

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
Public Sub setShape()Sub setShape(ByRef drawStrategy As IDrawStrategy)
InBlock.gif    _drawStrategy 
= drawStrategy
ExpandedSubBlockEnd.gif  
End Sub

ExpandedBlockEnd.gif
End Class

None.gif
ExpandedBlockStart.gifContractedBlock.gif
Interface IPaintInterface IPaint
ExpandedSubBlockStart.gifContractedSubBlock.gif  
Sub paint()Sub paint()
ExpandedBlockEnd.gif
End Interface

None.gif
ExpandedBlockStart.gifContractedBlock.gif
Class TriangleClass Triangle
InBlock.gif  
Implements IPaint
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
Public Sub paint()Sub paint() Implements IPaint.paint
InBlock.gif    Console.WriteLine(
"Draw Triangle")
ExpandedSubBlockEnd.gif  
End Sub

ExpandedBlockEnd.gif
End Class

None.gif
ExpandedBlockStart.gifContractedBlock.gif
Class CircleClass Circle
InBlock.gif  
Implements IPaint
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
Public Sub paint()Sub paint() Implements IPaint.paint
InBlock.gif    Console.WriteLine(
"Draw Circle")
ExpandedSubBlockEnd.gif  
End Sub

ExpandedBlockEnd.gif
End Class

None.gif
ExpandedBlockStart.gifContractedBlock.gif
Class SquareClass Square
InBlock.gif  
Implements IPaint
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
Public Sub paint()Sub paint() Implements IPaint.paint
InBlock.gif    Console.WriteLine(
"Draw Square")
ExpandedSubBlockEnd.gif  
End Sub

ExpandedBlockEnd.gif
End Class

None.gif
ExpandedBlockStart.gifContractedBlock.gif
Class DrawAdapterClass DrawAdapter(Of T As {IPaint, New})
InBlock.gif  
Implements IDrawStrategy
InBlock.gif
InBlock.gif  
Protected _adaptee As T = New T
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
Public Sub draw1()Sub draw1() Implements IDrawStrategy.draw
InBlock.gif    _adaptee.paint()
ExpandedSubBlockEnd.gif  
End Sub

ExpandedBlockEnd.gif
End Class

None.gif
ExpandedBlockStart.gifContractedBlock.gif
Class ClientClass Client
ExpandedSubBlockStart.gifContractedSubBlock.gif  
Shared Sub Main()Sub Main()
InBlock.gif    
Dim grapher As New Grapher(New DrawAdapter(Of Triangle))
InBlock.gif    grapher.drawShape()
InBlock.gif
InBlock.gif    grapher.setShape(
New DrawAdapter(Of Circle))
InBlock.gif    grapher.drawShape()
InBlock.gif
InBlock.gif    grapher.setShape(
New DrawAdapter(Of Square))
InBlock.gif    grapher.drawShape()
ExpandedSubBlockEnd.gif  
End Sub

ExpandedBlockEnd.gif
End Class


執行結果

None.gif Draw Triangle
None.gifDraw Circle
None.gifDraw Square


62行

ExpandedBlockStart.gif ContractedBlock.gif Class DrawAdapter Class DrawAdapter(Of T As {IPaint, New})
InBlock.gif  
Implements IDrawStrategy
InBlock.gif
InBlock.gif  
Protected _adaptee As T = New T
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif  
Public Sub draw1()Sub draw1() Implements IDrawStrategy.draw
InBlock.gif    _adaptee.paint()
ExpandedSubBlockEnd.gif  
End Sub

ExpandedBlockEnd.gif
End Class


我第一次使用VB的泛型,不過我覺得VB泛型的語法挺好的,一目了然。

Conclusion
Design Pattern雖然是OO思維的產物,但很多時候可借用泛型讓Design Pattern更好用,如(原創) 我的Design Pattern之旅[3]:使用template改進Strategy Pattern (OO) (Design Pattern) (C/C++) (template) 及 (原創) 我的Design Pattern之旅[4]:使用Generic改進Strategy Pattern (OO) (Design Pattern) (.NET) (C#) 都曾經用泛型讓Strategy Pattern更加好用。CLI語言C#、VB、C++/CLI若要使用Generics,不能使用傳統Class Adapter的繼承方式,必須使用組合來delegation。C++/CLI因同時有Template和Generics,所以繼承和組合方法皆適用。

See Also
(原創) 我的Design Pattern之旅[3]:使用template改進Strategy Pattern (OO) (Design Pattern) (C/C++) (template)
原創) 我的Design Pattern之旅[4]:使用Generic改進Strategy Pattern (OO) (Design Pattern) (.NET) (C#)
(原創) 我的Design Pattern之旅[6] : Adapter Pattern (OO) (Design Pattern) (C/C++) (.NET) (C#) (C++/CLI) (VB)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值