关于c#:具体.Net类的依赖注入

Dependency Injection for concrete .Net classes

注入/隔离类的首选方法是什么?这些类密封在DLL中,不实现接口?

我们使用NICATION。

假设我们有一个类"server",我们想注入/隔离"server"使用的类tcpserver。

我不想太具体,因为我想知道最好的方法,但我们可以这样说:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Server
{
    IServer _server;
    public Server(IServer server)
    {
        _server = server;
    }

    public void DoSomething()
    {
        _server.DoSomething();    
    }
}

比如,在测试时,应该给_server注入tcpclient或mock。


如果TcpServer是密封的,并且没有实现任何接口,但您仍然希望将客户机与其特定实现分离,则必须定义客户机可以与之对话的接口,以及从TcpServer到新接口的适配器。

从具体类中提取接口可能很有诱惑力,但不要这样做。它在接口和具体的类之间创建了一个语义耦合,您很可能最终打破了Liskov替换原则。

相反,根据客户机需要定义接口。这遵循依赖倒置原则;正如APPP,第11章解释的那样:"客户机[…]拥有抽象接口"。角色接口是最好的。

因此,如果您的客户机需要一个DoSomething方法,那么这就是您添加到接口中的全部内容:

1
2
3
4
public interface IServer
{
    void DoSomething();
}

现在可以使用构造函数注入将IServer注入到客户机中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Client
{
    private readonly IServer server;

    public Client(IServer server)
    {
        if (server == null)
            throw new ArgumentNullException("server");

        this.server = server;
    }

    public void DoFoo()
    {
        this.server.DoSomething();    
    }
}

当涉及到TcpServer时,可以在其上创建适配器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class TcpServerAdapter : IServer
{
    private readonly TcpServer imp;

    public TcpServerAdapter(TcpServer imp)
    {
        if (imp == null)
            throw new ArgumentNullException("imp");

        this.imp = imp;
    }

    public void DoSomething()
    {
        this.imp.DoWhatever();
    }
}

注意,这些方法不必具有相同的名称(甚至完全相同的签名),以便进行修改。