2009-08-19 10 views
21

J'essaie de comprendre le modèle d'adaptateur et son utilisation dans le monde réel. Après avoir parcouru divers articles sur internet et www.dofactory.com, j'ai créé cet exemple de code. Je veux juste savoir si ma compréhension est correcte. Dans l'exemple ci-dessous, j'ai créé un objet MSDAO dans la classe Adapter. Plus tard, je l'ai changé pour OracleDAO.Comprendre le modèle d'adaptateur

class Client 
{ 
    static void Main(string[] args) 
    { 
    ITarget objAdapter = new Adapter(); 
    object dummyObject = objAdapter.GetData(); 
    } 
} 

Interface ITarget 
{ 
    public void GetData(); 
} 

//Decision to use MSDAO 

class Adapter : ITarget 
{ 
    public void GetData() 
    { 
    MSDAO objmsdao = new MSDAO(); 
    objmsdao.GetData(); 
    } 
} 

//After a month, the decision to use OracaleDAO was taken, so the code change 

class Adapter : ITarget 
{ 
    public void GetData() 
    { 
    OracleDAO objoracledao = new OracleDAO(); 
    objoracledao.GetData(); 
    } 
} 

Répondre

61

En général, le modèle d'adaptateur transforme une interface dans une autre, mais il peut simplement envelopper le comportement d'isoler votre classe de la mise en œuvre sous-jacente. Dans votre cas, vous utilisez un adaptateur, mais vous pourriez tout aussi bien avoir défini les objets DAO pour simplement implémenter l'interface et la programmer sur l'interface. Le modèle d'adaptateur est généralement utilisé lorsque vous n'avez aucun contrôle sur la classe cible. Ma principale utilisation du modèle d'adaptateur consiste à créer des wrappers pour une classe de structure qui n'implémente pas d'interface. Dites que je veux créer une classe de structure qui n'implémente pas d'interface (et qui ne possède pas de méthodes virtuelles). Avec de nombreux apis moqueurs, c'est difficile ou impossible à faire. Ce que je ferai, alors, est de définir ma propre interface comme un sous-ensemble de la signature de la classe que je vise. J'implémente une classe wrapper qui implémente cette interface et délègue simplement les appels à la classe de framework enveloppé. Cette classe wrapper fonctionne comme un adaptateur pour la classe de structure. Mes classes utilisent cet adaptateur au lieu de la classe de structure, mais obtiennent le comportement de la classe de structure.

public interface IFoo 
{ 
    void Bar(); 
} 

public class FooWrapper : IFoo 
{ 
     private FrameworkFoo Foo { get; set; } 

     public FooWrapper(FrameworkFoo foo) 
     { 
      this.Foo = foo; 
     } 

     public void Bar() 
     { 
      this.Foo.Bar(); 
     } 
} 

Il faut aussi considérer le cas où vous avez deux ou trois différentes classes qui ont essentiellement les mêmes fonctionnalités, mais différentes signatures et que vous voulez être en mesure de les utiliser de manière interchangeable. Si vous ne pouvez pas les transformer (ou si vous ne le souhaitez pas pour d'autres raisons), vous pouvez écrire une classe d'adaptateur qui définit une interface commune et traduit entre les méthodes de cette interface et les méthodes disponibles sur les classes cibles.

classes Cadre:

public class TargetA 
{ 
    public void Start() { ... } 
    public void End() { ... } 
} 

public class TargetB 
{ 
    public void Begin() { ... } 
    public void Terminate() { ... } 
} 

un adaptateur pour les

public interface ITargetAdapter 
{ 
    void Open(); 
    void Close(); 
} 

public class AdapterA : ITargetAdapter 
{ 
    private TargetA A { get; set; } 

    public AdapterA(TargetA a) 
    { 
      this.A = a; 
    } 

    public void Open() { this.A.Start(); } 
    public void Close() { this.A.End(); } 
} 

public class AdapterB : ITargetAdapter 
{ 
    private TargetB B { get; set; } 

    public AdapterB(TargetB a) 
    { 
      this.B = a; 
    } 

    public void Open() { this.B.Begin(); } 
    public void Close() { this.B.Terminate(); } 
} 

ensuite utilisé comme:

ITargetAdapter adapter = new AdapterA(new TargetA()); 
adapter.Open(); 
adapter.Close();  
+0

Dans votre exemple, vous avez enveloppé votre classe de structure avec une classe qui implémente une interface. Je l'ai compris, mais pouvez-vous clarifier comment vous avez "transformé une interface en une autre?" – pradeeptp

+0

Dans ce cas, l'interface n'existait pas auparavant, c'est en quelque sorte un cas dégénéré dans le fait que vous êtes en train de créer une interface. interface pour une classe qui n'en a pas.Le deuxième exemple (juste ajouté) le démontre mieux – tvanfosson

+0

Merci beaucoup, c'est clair maintenant! – pradeeptp

2

Un exemple canonique dans le framework .NET existe dans la classe System.Drawing.Bitmap.

Ce Bitmap a un constructeur qui vous permet de charger une image à partir d'un Stream:

public Bitmap(
    Stream stream 
) 

ce que vous ne savez pas, est que l'intérieur de la classe Bitmap .NET est une enveloppe autour de la classe GDI + Bitmap, et son constructeur qui prend un IStream:

Bitmap(
    [in] IStream *stream, 
    [in] BOOL useIcm 
); 

Ainsi, dans le monde C#, quand je l'appelle:

new Bitmap(stream); 

il doit tourner autour et appeler:

IStream stm; 
IntPtr gpBitmap; 
GdipCreateBitmapFromStream(stm, out gpBitmap); 

La question est de savoir comment présenter une.NET Flux objet à une méthode qui attend une interface COM IStream.

D'où la classe GPStream interne:

internal class GPStream : IStream 
{ 
    GPStream(Stream stream) { ... } 
} 

Vous devez présenter une interface IStream à votre objet Stream:

IStream          Stream 
=======================================  ===================================== 
int Read(IntPtr buf, int len);   --> int Read(byte[] buffer, int offset, int count) 
int Write(IntPtr buf, int len);   --> void Write(byte[] buffer, int offset, int count); 
long Seek(long dlibMove, int dwOrigin); --> long Seek(long offset, SeekOrigin orgin) 
...           ... 

Alors maintenant, vous avez un adaptateur:

enter image description here

Et le code est quelque chose comme:

IStream stm = new GPStream(stream); //adapter to convert Stream --> IStream 
IntPtr gpBitmap; 

GdipCreateBitmapFromStream(stm, out gpBitmap); 
0

J'ai ajouté des commentaires qui nous l'espérons vous aider à obtenir votre entendu dans l'ensemble adaptateur/adaptee/client/jargon Itarget - qui est un peu déroutant - avec un exemple sera, espérons-le, plus intuitif - espérons-le :) (croisons les doigts).

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     // Brian and freddie know only how to say Greetings. But when they tour 
     // internationally, they will need a translator so when they say Greetings() 
     // the appropriate non-English response comes out of their mouth. 
     // they need to make use of the adapter pattern: 

     // When in Japan: 
     ITarget translator = new JapaneseTranslator(new JapaneseSpeaker()); 
     EnglishMan freddieMercury = new EnglishMan(translator); 

     // Freddie greets the Tokyo crowd, though he doesn't know a word of Japanese 
     Console.WriteLine(freddieMercury.Greetings()); // "Konichiwa, hisashiburi!" 

     // when in France: 
     ITarget translator2 = new FrenchTranslator(new FrenchSpeaker()); 
     EnglishMan brianMay = new EnglishMan(translator2); 

     // Brian greets the crowd in Paris, though he doesn't know a word in French 
     Console.WriteLine(brianMay.Greetings()); // "Bonjour!" 

     // alternatively, the translators can also do the greeting: 
     Console.WriteLine(translator.Greetings()); // "Konichiwa, hisashiburi!" 
     Console.WriteLine(translator2.Greetings()); // "Bonjour!" 
    } 

    /// <summary> 
    /// This is the client. 
    /// </summary> 
    public class EnglishMan : ITarget 
    { 
     private ITarget target; 

     public EnglishMan(ITarget target) 
     { 
      this.target = target; 
     } 

     public string Greetings() 
     { 
      return target.Greetings(); 
     } 
    } 

    /// <summary> 
    /// The target interface 
    /// </summary> 
    public interface ITarget 
    { 
     string Greetings(); 
    } 

    /// <summary> 
    /// This is the adaptor 
    /// </summary> 
    public class JapaneseTranslator : ITarget 
    { 
     private JapaneseSpeaker japanese; 

     public JapaneseTranslator(JapaneseSpeaker japanese) 
     { 
      this.japanese = japanese; 
     } 

     public string Greetings() 
     { 
      return japanese.Konnichiwa(); 
     } 
    } 

    /// <summary> 
    /// This is the adaptee 
    /// </summary> 
    public class JapaneseSpeaker 
    { 
     public JapaneseSpeaker() 
     { 
     } 

     public string Konnichiwa() 
     { 
      return "Konichiwa, hisashiburi!"; 
     } 
    } 

    /// <summary> 
    /// This is the adaptor 
    /// </summary> 
    public class FrenchTranslator : ITarget 
    { 
     private FrenchSpeaker french; 

     public FrenchTranslator(FrenchSpeaker french) 
     { 
      this.french = french; 
     } 

     public string Greetings() 
     { 
      return french.Bonjour(); 
     } 
    } 

    /// <summary> 
    /// This is the adaptee 
    /// </summary> 
    public class FrenchSpeaker 
    { 
     public string Bonjour() 
     { 
      return "Bonjour!!"; 
     } 
    } 
}