Comprender el Patrón del Adaptador


Estoy tratando de entender el patrón del adaptador y su uso en el mundo real. Después de pasar por varios artículos en internet y www.dofactory.com, He creado este código de ejemplo. Sólo quiero saber si mi entendimiento es correcto. En el siguiente ejemplo he creado el objeto MSDAO en la clase Adaptor. Más tarde lo cambié a OracleDAO.

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();
  }
}
Author: Richard Slater, 2009-08-19

3 answers

Generalmente el patrón de adaptador transforma una interfaz en otra, pero simplemente puede envolver el comportamiento para aislar su clase de la implementación subyacente. En su caso, está utilizando un adaptador, pero podría haber definido los objetos DAO para simplemente implementar la interfaz y programarlos contra la interfaz. El patrón de adaptador se usa generalmente cuando no tiene control sobre la clase de destino. Mi uso principal del patrón de adaptador sería crear envoltorios para una clase de framework que no implementa una interfaz.

Digamos que quiero burlarme de una clase de framework que no implementa una interfaz (y no tiene métodos virtuales). Con muchas api de burla esto es difícil o imposible de hacer. Lo que voy a hacer, entonces, es definir mi propia interfaz como un subconjunto de la firma de la clase que estoy apuntando. Implemento una clase wrapper que implementa esta interfaz y simplemente delega las llamadas a la clase wrapped framework. Esta clase wrapper funciona como adaptador para la clase framework. Mis clases usan este adaptador en lugar de la clase framework, pero obtienen el comportamiento de la clase framework.

 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();
      }
 }

Considere también el caso en el que tiene un par de clases diferentes que tienen básicamente la misma funcionalidad, pero diferentes firmas y desea poder usarlas indistintamente. Si no puede transformarlos (o no lo desea por otras razones), es posible que desee escribir una clase adapter que defina una interfaz común y traduce entre los métodos de esa interfaz y los métodos disponibles en las clases de destino.

Clases de framework:

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

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

Un adaptador para ellos

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(); }
}

Luego se usa como:

ITargetAdapter adapter = new AdapterA( new TargetA() );
adapter.Open();
adapter.Close();     
 72
Author: tvanfosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-19 11:25:33

Existe un ejemplo canónico dentro de. NET framework en el System.Drawing.Bitmap clase.

Este mapa de bits tiene un constructor que le permite cargar una imagen desde Stream:

public Bitmap(
    Stream stream
)

Lo que no sabes, es que internamente la clase. NET Bitmap es una envoltura alrededor del GDI+ Bitmap clase, y su constructor que toma un IStream:

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

Así que en el mundo de C#, cuando llamo: {[18]]}

new Bitmap(stream);

Tiene que dar la vuelta y llamada:

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

La pregunta es cómo presentar un objeto.NET Stream a un método que espera una interfaz COM IStream.

De ahí la clase interna GPStream:

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

Necesita presentar una interfaz IStream a su objeto 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)
...                                         ...

Así que ahora tienes un adaptador:

introduzca la descripción de la imagen aquí

Y el código es algo así como:

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

GdipCreateBitmapFromStream(stm, out gpBitmap);
 3
Author: Ian Boyd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-11 15:45:35

He añadido comentarios que espero que te ayuden a entender toda la jerga adaptador/adaptador/cliente/Itarget, lo cual es un poco confuso:

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 freddie = new EnglishMan(translator);

        // Freddie greets Tokyo, though he doesn't know a word of Japanese
        Console.WriteLine(freddie.Greetings()); //  "teo torriatte!"

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

        // Brian greets the crowd in Paris, though he doesn't know a word in French
        Console.WriteLine(brian.Greetings()); 
          // "So très charmant my dear! 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!!";
        }
    }
}
 3
Author: BKSpurgeon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-11 09:02:43