Подтвердить что ты не робот

Понимание шаблона адаптера

Я пытаюсь понять шаблон адаптера и его использование в реальном мире. Пройдя через различные статьи в Интернете и www.dofactory.com, я создал этот образец кода. Я просто хочу знать, правильно ли я понимаю. В приведенном ниже примере я создал объект MSDAO в классе Adapter. Позже я изменил его на 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();
  }
}
4b9b3361

Ответ 1

Как правило, шаблон адаптера преобразует один интерфейс в другой, но он может просто обернуть поведение, чтобы изолировать ваш класс от основной реализации. В вашем случае вы используете адаптер, но вы могли бы так же легко определить объекты DAO, чтобы просто реализовать интерфейс и запрограммировать его на интерфейс. Шаблон адаптера обычно используется, если у вас нет контроля над целевым классом. Мое основное использование шаблона адаптера состояло в создании оболочек для класса framework, который не реализует интерфейс.

Скажем, я хочу высмеять класс рамки, который не реализует интерфейс (и не имеет виртуальных методов). Со многими издевательскими apis это трудно или невозможно сделать. Тогда я буду определять свой собственный интерфейс как подмножество подписи класса, на который я нацелен. Я реализую класс-оболочку, реализующий этот интерфейс, и просто делегирует вызовы в класс оболочки. Этот класс-оболочка работает как адаптер для класса framework. Мои классы используют этот адаптер вместо класса framework, но получают поведение класса 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();
      }
 }

Рассмотрим также случай, когда у вас есть несколько разных классов, которые имеют в основном одну и ту же функциональность, но разные подписи, и вы хотите иметь возможность использовать их взаимозаменяемо. Если вы не можете их преобразовать (или не хотите по другим причинам), вы можете написать класс адаптера, который определяет общий интерфейс, и переводит между этими методами интерфейса и методами, доступными для целевых классов.

Рамочные классы:

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

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

Адаптер для них

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

Затем используется как:

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

Ответ 2

Канонический пример внутри рамки .NET существует в классе System.Drawing.Bitmap.

Этот битмап имеет конструктор, который позволяет загружать изображение из Stream:

public Bitmap(
    Stream stream
)

то, что вы не знаете, заключается в том, что внутри .NET класс Bitmap является оберткой класса GDI + Bitmap, и его конструктор, который принимает IStream:

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

Итак, в мире С#, когда я звоню:

new Bitmap(stream);

он должен развернуться и вызвать:

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

Вопрос заключается в том, как представить объект .NET Stream для метода, который ожидает интерфейс COM IStream.

Следовательно, внутренний GPStream класс:

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

Вам нужно представить интерфейс IStream для вашего объекта 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)
...                                         ...

Итак, теперь у вас есть адаптер:

введите описание изображения здесь

И код выглядит примерно так:

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

GdipCreateBitmapFromStream(stm, out gpBitmap);

Ответ 3

Я добавил комментарии, которые, мы надеемся, помогут вам услышать об этом весь jargon адаптера /adapttee/client/Itarget - что немного запутанно - с примером, который, мы надеемся, будет более интуитивным - надеюсь, надеюсь:) (пальцы пересекла).

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!!";
        }
    }
}