C# 静态材料的松耦合

C# 静态材料的松耦合,c#,static,dependency-injection,abstraction,C#,Static,Dependency Injection,Abstraction,我有一个类,ClassA,它使用我编写的客户端发送文本消息,TextClient,通过调用静态方法发送一些文本消息 TextClient.Send(string text, string destination) // where destination is a phone number 但是,我还有一个邮件客户端类,MailClient,它发送具有相同签名的电子邮件: MailClient.Send(string text, string destination) // where des

我有一个类,
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
可以保存并被认为有效时,可能会出现问题,但是这些值是从其他地方获取的,所以这个类不需要麻烦。这就是为什么我首先要将其抽象掉。)

在设计此类服务时,通常最好避免使用静态类,因为这样会使与其他代码分离变得更具挑战性

如果您可以控制
TextClient
MailClient
类的设计和实现,我建议您考虑将它们设置为实例类而不是静态类。然后,您可以在这两种语言中实现一个公共接口
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
class-SomeConsumer
{
私人行动代表;
公共用户(操作sendDelegate)
{ 
m_SendDelegate=SendDelegate;
} 
公共剂量测定法()
{
//使用提供的委托发送消息
m_SendDelegate(“待发送文本”、“目的地”);
}
}
var consumerA=newsomeconsumer(TextClient.Send);//发送短信
var consumerB=newsomeconsumer(MailClient.Send);//将发送电子邮件

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

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

  • 所涉及的名称(接口名称、方法名称和参数名称)在使用时传递信息
  • 它允许在同一接口中使用多个方法
  • 它可以防止碰巧具有相同参数类型但意义完全无关的方法被意外使用

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

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

      然后只需使用依赖项注入来选择要使用的发送方。

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

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

      如果无法使这些方法成为非静态的,您可以只写静态方法调用的精简包装器来实现上述接口。

      当然,请确保您的客户端实现一些发送接口

      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的回答相同,但他没有键入代码,这打败了我。

      除非
      Send()
      方法是非静态的,否则这将不起作用。因为我不拥有我想要进行实例化的对象,所以我希望不必这样做。但是我想我必须找到一些解决方法来使用这个模式。