静态物料的松散耦合

时间:2010-07-14 13:45:49

标签: 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 destination is an email address

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

(注意:我知道当destination可以容纳哪些值并且被认为有效时,可能会出现的问题可能会出现问题,但这些值是从其他地方获取的,所以这个上课并不需要打扰。这就是为什么我想首先把它抽象出去。)

5 个答案:

答案 0 :(得分:7)

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

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

  • 所涉及的名称(接口名称,方法名称和参数名称)在您使用时传达信息
  • 它允许在同一界面中使用多种方法
  • 它可以防止碰巧具有相同参数类型但意外使用的完全不相关的方法

答案 1 :(得分:4)

当然,让您的客户端实现一些发送界面。

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

答案 2 :(得分:2)

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

如果您可以控制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

答案 3 :(得分:1)

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

如果无法使方法成为非静态方法,则可以在静态方法调用周围写入瘦包装器,同时实现所述接口。

答案 4 :(得分:0)

我会这么认为的。如果您有这样的界面

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

然后使用依赖注入来获取要使用的发件人。