【问题标题】:How does Adapter Design Pattern work in C#?适配器设计模式在 C# 中如何工作?
【发布时间】:2013-03-14 15:35:32
【问题描述】:

我这里有一个适配器模式的示例(是的,您可以检查它是否正确实现),但我真正的问题是在这里,据说适配器设计模式执行以下操作:“将类的接口转换为另一个客户期望的接口。适配器允许类一起工作,否则由于接口不兼容而无法工作。但是我对那个说法有点困惑,根据我下面的代码,我不太明白,我想知道它发生在哪里。

这是我的类/接口:

public interface ILogger
{
      void Write(string data);
}

public class InfrastructureDebugLogger : ILogger
{
      public void Write(string data)
      {
           Debug.WriteLine(data);
      }
}

public class InfrastructureLoggerToDatabaseAdapter : ILogger
{
      private IRepository<Log> adaptee;

      public InfrastructureLoggerToDatabaseAdapter(IRepository<Log> adaptee)
      {
            this.adaptee = adaptee;
      }

      public void Write(string data)
      {
            var log = new Log() { Value = data };
            adaptee.Create(log);   
      }
}

public interface IRepository<T>
{
        void Create(T item);
        void Update(T item);
        T Find(int id);

}

public class Log
{
        public int ID { get; set; }
        public string Value { get; set; }
}

public class LogRepository : IRepository<Log>
{
        public void Create(Log item)
        {
            Console.WriteLine("Created an item inside the LogRepository");
        }

        public void Update(Log item)
        {
            throw new NotImplementedException();
        }

        public Log Find(int id)
        {
            throw new NotImplementedException();
        }
}

class Program
{
    static void Main(string[] args)
    {

            ILogger logger = new InfrastructureDebugLogger();
            Console.Write("Data: ");
            string data = Console.ReadLine();
            logger.Write(data);
            InfrastructureLoggerToDatabaseAdapter loggerToDatabaseAdapter = 
                new InfrastructureLoggerToDatabaseAdapter(new LogRepository());
            loggerToDatabaseAdapter.Write(data);
            Console.ReadKey();
     }
 }

【问题讨论】:

  • 您的适配器 InfrastructureLoggerToDatabaseAdapter 实际上命名不正确。它接收 IRepository 类型的对象并将其转换为 ILogger 类型。所以它实际上应该被称为 DatabaseToInfrastructureLoggerAdapter 或更准确地说是 RepositoryToLoggerAdapter。

标签: c# design-patterns adapter


【解决方案1】:

您的代码显示了适配器,但没有显示使用它作为适配器。

要使用此适配器,您需要通过适配器使用实现IRepository&lt;Log&gt;LogRepository 作为ILogger。比如:

class Program
{
    static void Main(string[] args)
    {

        Console.Write("Data: ");
        string data = Console.ReadLine();
        InfrastructureLoggerToDatabaseAdapter loggerToDatabaseAdapter = 
            new InfrastructureLoggerToDatabaseAdapter(new LogRepository());

        // Here, you're using a IRepository<Log>, but adapting it to be used as an ILogger...
        ILogger logger = loggerToDatabaseAdapter;
        logger.Write(data);
        Console.ReadKey();
    }
}

【讨论】:

    【解决方案2】:

    简单来说——

    1. 重命名您的适配器,因为它实际上不是 InfrastructureLoggerToDatabaseAdapter,而是一个 Repository to Logger 类型。由于您传递的是 IRepository 类型对象并期望它的行为类似于 ILogger。

    2. 由于存储库现已更新为 ILog 类型对象,您应该使用 ILogger 变量对其进行操作。

    代码:

    public class RepositoryToLoggerAdapter : ILogger
        {
            private IRepository adaptee;
    
            public InfrastructureLoggerToDatabaseAdapter(IRepository adaptee)
            {
                this.adaptee = adaptee;
            }
    
            public void Write(string data)
            {
                var log = new Log() { Value = data };
                adaptee.Create(log);   
            }
        }
    
    class Program
        {
            static void Main(string[] args)
            {
    
                ILogger logger = new InfrastructureDebugLogger();
                Console.Write("Data: ");
    
                string data = Console.ReadLine();
    
          //This step is redundant as the text will be shown on the screen as you type
    logger.Write(data);
    
    //Create an object of IRepository type.
    IRepository repository= new LogRepository();
    
    //The create method works as it should
    repository.Create(data);
    
    
    //You could not have stored the repository object in the logger variable if you did not have this adapter.
    
                logger = new RepositoryToLoggerAdapter(repository);
    
    //Effectively you now are calling the Create method of the Repository by calling the Write method of the logger.
    
                logger.Write(data);
                Console.ReadKey();
            }
        }
    

    希望这是有道理的。如果有不清楚的地方请告诉我。

    【讨论】:

    • 感谢您的解决方案,它解释得很好。只是有一个问题,如果我这样做会不会有区别:logger = new RepositoryToLoggerAdapter(new LogRepository()) since LogRepository implements IRepository?
    • 当然可以。我只是写了它,以便更容易理解。
    【解决方案3】:

    将一个类的接口转换为客户期望的另一个接口。 Adapter 可以让那些因为接口不兼容而无法协同工作的类一起工作。

    在这种情况下,您有一个IRepository&lt;Log&gt;,但您必须是一个ILogger,即“客户期望的另一个接口”。适配器类通过封装IRepository&lt;Log&gt; 并将ILogger 调用转换为IRepository&lt;Log&gt; 调用来实现这一点。

    【讨论】:

      【解决方案4】:

      从您的示例中不清楚,因为您没有需要记录器的客户端。考虑以下课程:

      public class Foo
      {
          private ILogger _logger;
      
          public Foo(ILogger logger)
          {
               _logger = logger;
          }
      
          public void Bar()
          {
             _logger.Write("Bar is called");
             // do something
          }
      }
      

      您不能将LogRepository 传递给此类。因为LogRepository 没有实现ILogger 接口。但是使用适配器,您可以将IRepository&lt;Log&gt; 接口“转换”为Foo 类所需的ILogger 接口:

      class Program
      {
          static void Main(string[] args)
          {
              // you can't pass repository to Foo
              LogRepository repository = new LogRepository();            
      
              InfrastructureLoggerToDatabaseAdapter loggerToDatabaseAdapter = 
                  new InfrastructureLoggerToDatabaseAdapter(repository);
      
              // but you can pass adapter
              Foo foo = new Foo(loggerToDatabaseAdapter);
              foo.Bar();
      
              Console.ReadKey();
          }
      }
      

      实际工作仍由LogRepository 班级完成。适配器只是将其接口调整为客户端所需的接口。插座适配器的工作方式相同。如果你有电动剃须刀,应该插在美国插座上,如果没有适配器,你就不能在欧洲使用它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多