了解适配器模式

发布于 2024-08-01 20:15:27 字数 765 浏览 7 评论 0原文

我试图了解适配器模式及其在现实世界中的使用。 在浏览了互联网和 www.dofactory.com 上的各种文章后,我创建了这个示例代码。 我只是想知道我的理解是否正确。 在下面的示例中,我在 Adapter 类中创建了 MSDAO 对象。 后来我把它改成了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();
  }
}

I am trying to understand Adapter pattern and its use in real world. After going through various articles on internet and www.dofactory.com, I created this sample code. I just want to know whether my understanding is correct. In the example below I have created MSDAO object in the Adaptor class. Later I changed it to 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();
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

与之呼应 2024-08-08 20:15:27

通常,适配器模式将一个接口转换为另一个接口,但它可以简单地包装行为以将您的类与底层实现隔离。 在您的例子中,您使用的是适配器,但您可以轻松地定义 DAO 对象来简单地实现接口并针对接口进行编程。 当您无法控制目标类时,通常会使用适配器模式。 我对适配器模式的主要用途是为不实现接口的框架类创建包装器。

假设我想模拟一个没有实现接口(并且没有虚拟方法)的框架类。 对于许多模拟 API,这是很难或不可能做到的。 然后,我要做的就是将我自己的接口定义为我所针对的类的签名的子集。 我实现了一个包装类,该类实现了该接口,并简单地将调用委托给包装的框架类。 该包装类充当框架类的适配器。 我的类使用此适配器而不是框架类,但获得框架类的行为。

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

Generally the adapter pattern transforms one interface into another, but it can simply wrap the behavior to isolate your class from the underlying implementation. In your case, you are using an adapter, but you could just as easily have defined the DAO objects to simply implement the interface and programmed against the interface. The adapter pattern is usually used when you don't have control over the target class. My primary use of the adapter pattern would be to create wrappers for a framework class that doesn't implement an interface.

Say I want to mock out a framework class which doesn't implement an interface (and doesn't have virtual methods). With many mocking apis this is hard or impossible to do. What I will do, then, is define my own interface as a subset of the signature of the class I'm targeting. I implement a wrapper class that implements this interface and simply delegates the calls to the wrapped framework class. This wrapper class works as an adapter for the framework class. My classes use this adapter instead of the framework class, but get the framework class' behavior.

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

Consider also the case where you have a couple of different classes that have basically the same functionality, but different signatures and you want to be able to use them interchangeably. If you can't transform these (or don't want to for other reasons), you may want to write an adapter class that defines a common interface and translates between that interface's methods and the methods available on the target classes.

Framework classes:

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

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

An adapter for them

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

Then used as:

ITargetAdapter adapter = new AdapterA( new TargetA() );
adapter.Open();
adapter.Close();     
梦幻的味道 2024-08-08 20:15:27
internal class Program
{
    private static void Main(string[] args)
    {
        // When in foreign countries, and you want to say hello
        // just say "hello" and then 
        // the appropriate non-English response comes out 

        // When in Japan:
        var 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!!";
        }
    }
}
internal class Program
{
    private static void Main(string[] args)
    {
        // When in foreign countries, and you want to say hello
        // just say "hello" and then 
        // the appropriate non-English response comes out 

        // When in Japan:
        var 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!!";
        }
    }
}
你与清晨阳光 2024-08-08 20:15:27

.NET 框架内的规范示例位于 System.Drawing.Bitmap 类。

此位图有一个构造函数,可让您从 Stream

public Bitmap(
    Stream stream
)

您不知道的是,.NET Bitmap 类在内部是 GDI+ 位图类,及其构造函数采用 IStream

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

所以在 C# 世界中,当我调用:

new Bitmap(stream);

它必须转身调用:

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

问题是如何呈现一个 . NET Stream 对象到需要 COM IStream 接口的方法。

因此,内部 GPStream 类:

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

您需要向您的 Stream 对象提供一个 IStream 接口:

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

A canonical example inside the .NET framework exists in the System.Drawing.Bitmap class.

This Bitmap has a constructor that lets you load an image from a Stream:

public Bitmap(
    Stream stream
)

what you don't know, is that internally the .NET Bitmap class is a wrapper around the GDI+ Bitmap class, and its constructor that takes an IStream:

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

So in the C# world, when i call:

new Bitmap(stream);

it has to turn around and call:

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

The question is how to present a .NET Stream object to a method that expects a COM IStream interface.

Hence the internal GPStream class:

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

You need to present an IStream interface to your Stream object:

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)
...                                         ...

So now you have an adapter:

enter image description here

And the code is something like:

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

GdipCreateBitmapFromStream(stm, out gpBitmap);
自由如风 2024-08-08 20:15:27

一个非常简单的例子......

 interface ITarget
    {
      List<string> GetProducts();
    }


    public class VendorAdaptee
    {
       public List<string> GetListOfProducts()
       {
          List<string> products = new List<string>();
          products.Add("Gaming Consoles");
          products.Add("Television");
          products.Add("Books");
          products.Add("Musical Instruments");
          return products;
       }
    }


    class VendorAdapter:ITarget
    {
       public List<string> GetProducts()
       {
          VendorAdaptee adaptee = new VendorAdaptee();
          return adaptee.GetListOfProducts();
       }
    }


    class ShoppingPortalClient
    {
       static void Main(string[] args)
       {
          ITarget adapter = new  VendorAdapter();
          foreach (string product in adapter.GetProducts())
          {
            Console.WriteLine(product);
          }
          Console.ReadLine();
       }
    }

A very simple example...

 interface ITarget
    {
      List<string> GetProducts();
    }


    public class VendorAdaptee
    {
       public List<string> GetListOfProducts()
       {
          List<string> products = new List<string>();
          products.Add("Gaming Consoles");
          products.Add("Television");
          products.Add("Books");
          products.Add("Musical Instruments");
          return products;
       }
    }


    class VendorAdapter:ITarget
    {
       public List<string> GetProducts()
       {
          VendorAdaptee adaptee = new VendorAdaptee();
          return adaptee.GetListOfProducts();
       }
    }


    class ShoppingPortalClient
    {
       static void Main(string[] args)
       {
          ITarget adapter = new  VendorAdapter();
          foreach (string product in adapter.GetProducts())
          {
            Console.WriteLine(product);
          }
          Console.ReadLine();
       }
    }
心凉怎暖 2024-08-08 20:15:27

我会保持非常简单。 如果一个调用者想要调用 MSDAOGetData 方法,而另一个调用者想要调用 OracleDAO,该怎么办?
或者将来还可以添加其他类。

在这种情况下,您的解决方案将不起作用。

因此,我建议将 GetData 方法声明为适配器类的虚拟方法。
添加新的适配器类,扩展适配器类并实现您的 ITarget 接口,并相应地实现 GetData(声明它override)方法。

如果以后有新课程,请重复上述步骤。

I’ll keep it very simple. What if one caller wants to call the GetData method of MSDAO and other caller wants OracleDAO.
Or in future other class can also be added.

In that case your solution will not work.

So I would suggest to declare the GetData method as virtual of the adaptee class.
Add a new adapter class, extend the adaptee class and implement your ITarget interface and implement the GetData (declare it override) method accordingly.

Repeat the above step if you will have new class in future.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文