用IoC(Castle Windsor)替换以下代码

4
如果我有以下代码,使用IoC(我们计划使用Castle Windsor)替换它的最佳实践/设计考虑是什么?由于“using”语句负责创建连接对象,因此无法直接将其注入构造函数或方法中。注意:在这里使用SQL连接作为一个干净的例子,主要好处是模拟/单元测试。
public void CustomerRespository
{
    ....
    public void Save(Customer customer)
    {
       using (var cn = new SqlConnection(connectionString))
       {
           using (var cm = new SqlCommand(commandString, cn))
           {
              ....
              cn.Open();
              cm.ExecuteNonQuery();
           }
       }
    }
}

我相信至少有几个选项可供选择,但由于我们刚刚开始使用IoC,我不确定它们是否会在以后引起问题和/或与IoC的概念相抵触。我的首选方法是修改方法如下,有人能否指出潜在问题?

public interface IDatabase
{
    IDbConnection Connection(string connectionString);
    IDbCommand Command(string text, IDbConnection conn);
}

public class SqlDB : IDatabase
{
    IDbConnection Connection(string connectionString)
    { return new SqlConnection(connectionString); }

    IDbCommand Command(string text, IDbConnection conn)
    { return new SqlCommand(text, conn); }
}

public interface ICustomerRespository
{
   void Save(Customer customer)
}

public class CustomerRespository : ICustomerRespository
{
    public IDatabase DB{get; private set;}

    public CustomerRespository( IDatabase db)
    {
       DB = db;
    }

    ....
    public void Save(Customer customer)
    {
       using (var cn = DB.Connection(connectionString))
       {
           using (var cm = DB.Command(commandString, cn))
           {
              ....
              cn.Open();
              cm.ExecuteNonQuery();
           }
       }
    }
}

请使用 var cmd = con.CreateCommand() 替代 new SqlCommand(str, cn)。 - jgauffin
@M4N,谢谢已经更新为“var”。@JQauffin:好主意,现在为了保持代码示例的一致性,我将保留“原样”,但会从我提案的IDatabase接口实现者中移除一个责任。 - Paul Hadfield
2个回答

1

我使用过IoC,但没有用过Castle,虽然它们都很相似,这是我的看法。

我认为你走在了正确的道路上 - 虽然我可能会为连接和命令使用单独的工厂,或者实际上将连接打开和命令运行到另一个类中,以便存储库不必知道这个细节。只需在类的构造函数中拥有IDatabase,以便注入(如果您正在使用基于属性的注入,则使用属性)。在代码中用IDbConnection和IDbCommand替换SqlConnection和SqlCommand。

更新

它们确实继承/实现IDisposable,因此您可以使用using语句。对我的错误表示抱歉。


@Alistad,我刚刚查看了MSDN接口的定义,它说这两个接口确实继承自IDisposable。http://msdn.microsoft.com/en-us/library/system.data.idbconnection.aspx和http://msdn.microsoft.com/en-us/library/system.data.idbcommand.aspx - Paul Hadfield

1

总的来说,这种方法对我来说很好,尽管我不会尝试模拟IDbConnectionIDbCommand接口,因为那可能会很复杂,更重要的是无法告诉您代码是否按预期工作。

但它可以让您更改所使用的数据库,因此您可以在单元测试中使用类似Sqlite的东西,然后在集成测试期间针对生产数据库测试代码。

您还可以将连接字符串移动到IDatabase抽象中,这将简化客户端。


整理连接字符串是个好主意,我之前将其保留在示例代码中是为了让代码长度合理。使用 Moq,我不会想要模拟整个IDbConnection或repository,只需要与测试相关的部分(如超时或不可用)即可。 - Paul Hadfield

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接