【问题标题】:Loose coupling of static stuff静态材料的松散耦合
【发布时间】:2011-03-15 20:57:50
【问题描述】:

我有一个类ClassA,它使用我编写的客户端发送短信,TextClient,通过调用静态方法发送一些短信

TextClient.Send(string text, string destination)
// where destination is a phone number

不过,我还有一个邮件客户端类MailClient,它发送具有相同签名的电子邮件:

MailClient.Send(string text, string destination)
// where destination is an email address

我想“注入”应该使用哪些客户端 - 这可能吗?

(注意:我知道当 destination 可以持有并被认为有效的值有完全不同的规则时可能会出现问题,但是这些值是从其他地方获取的,所以这个类不不需要麻烦。这就是为什么我想首先将其抽象出来。)

【问题讨论】:

    标签: c# static dependency-injection abstraction


    【解决方案1】:

    基本上,摆脱静态方法。创建一个接口(@98​​7654321@),然后创建两个实现(TextClientMailClient),并使用实现该接口的实例方法。然后,您可以轻松地将适当的IMessageClient 注入应用程序的其余部分。

    您当然可以使用委托来避免在这里创建接口 - 但我肯定会改为使用接口:

    • 所涉及的名称(接口名称、方法名称和参数名称)在您使用它们时传达信息
    • 它允许在同一个接口中使用多个方法
    • 它可以防止偶然使用具有相同参数类型但完全不相关含义的方法

    【讨论】:

    • 因为我不拥有我想要进行实例化的对象,所以我希望我不必走这条路。但我想我必须找到一些解决方法来使用这种模式。
    【解决方案2】:

    当然,让你的客户端实现一些发送接口。

    public interface IMessageClient
    {
        public void Send(string text, string destination);
    }
    
    public class TextClient : IMessageClient
    {
        public void Send(string text, string destination)
        {
            // send text message
        }
    }
    
    public class MailClient : IMessageClient
    {
        public void Send(string text, string destination)
        {
            // send email
        }
    }
    
    public class ClassA
    {
        private IMessageClient client;
    
        public ClassA(IMessageClient client)
        {
            this.client = client;
        }
    }
    

    与 Jon Skeet 的回答相同,但他通过不输入代码击败了我。

    【讨论】:

      【解决方案3】:

      在设计此类服务时,通常最好避免使用静态类,因为它使与其他代码解耦变得更具挑战性。

      如果您可以控制TextClientMailClient 类的设计和实现,我建议考虑将它们设为singleton 实例类而不是静态类。然后,您可以在两者中实现一个通用接口IMessageSender(见下文),并将其作为实例传递给需要进行调用的对象。

      public interface IMessageSender
      {
          void Send( string message, string destination );
      }
      
      public class TextClient : IMessageSender { ... }
      public class MailClient : IMessageSender { ... }
      

      如果您无法控制这些类的实现(或此时无法更改它们),您可以将委托传递给需要进行调用的对象:

      class SomeConsumer
      {
          private Action<string,string> m_SendDelegate;
          public SomeConsumer( Action<string,string> sendDelegate ) 
          { 
              m_SendDelegate = sendDelegate;
          } 
      
          public DoSomething()
          {
              // uses the supplied delegate to send the message
              m_SendDelegate( "Text to be sent", "destination" ); 
          }
      }
      
      var consumerA = new SomeConsumer( TextClient.Send ); // sends text messages
      var consumerB = new SomeConsumer( MailClient.Send ); // will send emails
      

      【讨论】:

        【解决方案4】:

        不要将方法设为静态,使用Send()方法创建一个接口,并在TextClientMailClient 上实现此接口。现在您可以使用接口注入一个实例。

        如果无法使方法成为非静态方法,您可以只编写围绕静态方法调用的瘦包装器,两者都实现了所述接口。

        【讨论】:

          【解决方案5】:

          我会这么想的。如果你有这样的接口

          public interface ISender
          {
          void Send(string text, string destination);
          }
          

          然后只需使用依赖注入来选择要使用的发件人。

          【讨论】:

          • 除非将Send() 方法设为非静态,否则这将不起作用。
          猜你喜欢
          • 2018-07-29
          • 2017-06-05
          • 2020-10-26
          • 2011-02-22
          • 2010-10-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-10-11
          相关资源
          最近更新 更多