Dependency injection 使类遵循OCP-将函数分解为对象

Dependency injection 使类遵循OCP-将函数分解为对象,dependency-injection,single-responsibility-principle,open-closed-principle,Dependency Injection,Single Responsibility Principle,Open Closed Principle,我有一个我不断增加的课程 public class OrderRepository{ public void Add(IEnumerable<Order> orders){} public void Update(IEnumerable<Order> orders){} public void Remove(IEnumerable<Order> orders){} public void Expedite(IEnumerable

我有一个我不断增加的课程

public class OrderRepository{
    public void Add(IEnumerable<Order> orders){}
    public void Update(IEnumerable<Order> orders){}
    public void Remove(IEnumerable<Order> orders){}
    public void Expedite(IEnumerable<Order> orders){}
    public void GetOrderData(Order order, DateTime start, DateTime end)
    etc...
}
这使得OrderRepository打开进行扩展,关闭进行修改。但是,我很快就遇到了一些问题:

1.)请求需要操作的数据由用户提供(运行时)和依赖项注入。我显然不能用一个构造函数同时满足这两个要求。我做不到:

public class AddRequest{
    public AddRequest(IEnumerable<Order> orders, int UserSuppliedContextArg1, DependencyInjectionArg1, DependencyInjectionArg2);
}
这并不坏,但API很难看。现在,这个对象的客户端需要“构造”它两次。如果他们忘记调用PackArgs,我必须抛出某种异常

我可以继续说下去,但这些是我目前面临的最令人困惑的问题。有什么想法吗?

Ayende有个主意

基本上,您要做的是将查询从存储库中分离出来,并将查询转换为您编写的内容。使用由组合构造的查询,您可以轻松地对其进行扩展,以添加新的查询方式,而无需向存储库添加新方法。你可以得到这样的结果:

public class Repository<T>
{
   T Find(IQueryCriteria queryCriteria);
}
var query = new EmployeeQuery()
   .WithLastName("Holmes")
   .And()
   .InDepartment("Information Systems");

var employee = repository.Find(query);

扩展存储库的功能相当于简单地在查询对象上添加新方法

存储库是您域的一部分。让它成为通用语言,虽然很诱人,但却违背了它作为无所不在语言中操作之家的目的。如果您可以使用存储库做任何事情,那么您已经混淆了它的意图


如果一个类遵循SRP,“不断添加到”它违反了定义。这表明您正在引入的操作可以由服务更好地解决,或者应该与存储库分离

根据评论进行编辑

您希望将您无处不在的语言公开,同时确保类承担最小的责任

从存储库中分离操作将是第一步。你可以这样做:

public interface IOrderExpeditionService
{
    void Expedite(IEnumerable<Order> orders);
}

public interface IOrderDataService
{
    void GetOrderData(Order order, DateTime start, DateTime end);
}
公共接口IORDexpeditionService
{
作废催交单(IEnumerable orders);
}
公共接口IOrderDataService
{
void GetOrderData(订单、日期时间开始、日期时间结束);
}

这看起来有些有用,但我的问题更多的是封装请求,而不是查询。此外,我不会访问存储库后面的数据库,尽管这可能不重要。“这表明您正在引入的操作可能更好地由服务解决,或者应该与存储库分离。”-这就是我一直在尝试的。你对解耦部分有什么建议吗?回答得很好。不过,我会将这些服务实现为类。更简单的是,单元测试它们甚至依赖于它们的类仍然很容易。我选择使用接口来表示接口,而不是使用抽象类来做同样的事情。各自为政。
public AddRequest{
    public AddRequest(DependencyInjectionArg1, DependencyInjectionArg2, ...){}

    public void PackArgs(UserSuppliedContextArg1, UserSuppliedContextArg2, UserSuppliedContextArg3, ...){}
}
public class Repository<T>
{
   T Find(IQueryCriteria queryCriteria);
}
var query = new EmployeeQuery()
   .WithLastName("Holmes")
   .And()
   .InDepartment("Information Systems");

var employee = repository.Find(query);
public interface IOrderExpeditionService
{
    void Expedite(IEnumerable<Order> orders);
}

public interface IOrderDataService
{
    void GetOrderData(Order order, DateTime start, DateTime end);
}