设计依赖注入类的指南

Geo*_*uer 6 inversion-of-control

关于单元测试最佳实践的这个问题提到了为依赖注入设计类.这让我想到了究竟是什么意思.

刚刚开始使用控制容器的反转,我对这个问题有一些想法,所以让我把它们扔到墙上看看有什么问题.

我看到它的方式,对象可以有三种基本类型的依赖项.

  1. 对象依赖关系 - 将由相关类使用的实际对象.例如LogInFormController中的LogInVerifier.这些应该通过构造函数注入.如果类足够高,在构造函数中需要超过4个这些对象,请考虑将其分解或至少使用工厂模式.您还应该考虑使用接口提供依赖关系并对接口进行编码.
  2. 简单设置 - 例如阈值或超时时间.这些通常应具有默认值,并通过工厂模式的构建器进行设置.您还可以提供设置它们的构造函数重载.但是在大多数情况下,您可能不应该强制客户端必须明确地进行设置.
  3. 消息对象 - 从一个类传递到另一个类的对象,接收类可能用于业务逻辑.一个示例是LogInCompleRouter类的User对象.在这里我发现通常更好的是不在构造函数中指定消息,因为您必须使用IoC容器注册User实例(使其成为全局)或者在您拥有User实例之后不实例化LogInCompleteRouter (你不能使用DI或至少需要对Container的显式依赖).在这种情况下,最好只在需要方法调用时传入消息对象(即LoginInCompleteRouter.Route(User u);).

另外,我应该提一下,并不是所有东西都应该是DI,如果你有一个简单的功能,只是方便分解到一个扔掉的类,它可能可以在现场实例化.显然这是一个判断力; 如果我发现写一个类的权宜之计

class PasswordEqualsVerifier {
  public bool Check(string input, string actual) { return input===actual;}
}
Run Code Online (Sandbox Code Playgroud)

我可能不会打扰依赖注入它,只是让一个对象直接在using块中实例化它.其必然结果是,如果值得编写单元测试,则可能值得注入.

那你觉得怎么样?欢迎任何其他指南或对比意见.

dav*_*000 1

重要的是尝试对接口进行编码,并让您的类接受这些接口的实例,而不是自己创建实例。显然你可能会对此感到疯狂,但无论单元测试还是 DI,这都是一个通用的良好实践。

例如,如果您有一个数据访问对象,您可能倾向于为所有 DAO 编写一个基础,如下所示:

public class BaseDAO
{
    public BaseDAO(String connectionURL, 
                   String driverName, 
                   String username, String password)
    {
        // use them to create a connection via JDBC, e.g.
    }

    protected Connection getConnection() { return connection; }
}
Run Code Online (Sandbox Code Playgroud)

但是,最好从类中删除它以支持接口

public interface DatabaseConnection
{
    Connection getConnection();
}

public class BaseDAO
{
    public BaseDAO(DatabaseConnection dbConnection)
    {
        this.dbConnection = dbConnection;
    }

    protected Connection getConnection() { return dbConnection.getConnection(); }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以提供多种实现DatabaseConnection. 即使忽略单元测试,如果我们假设我们使用 JDBC,有两种方法可以获取Connection:从容器中获取连接池,或者直接通过使用驱动程序。现在,您的 DAO 代码未与任一策略耦合。

为了进行测试,您可以使用MockDatabaseConnection预设数据连接到某些嵌入式 JDBC 实现来测试您的代码。