在DDD中,是应用层,使用存储库从数据库中获取数据,调用域的方法,然后调用存储库来持久化数据。类似的东西:
public void MyApplicationService()
{
Order myOrder = _orderRepository.Get(1);
myOrder.Update(data);
_orderRepository.Commit();
}
在本例中,存储库是一个类变量,它在服务的构造函数中实例化,因此它的生命周期就是类的生命周期。
但我想知道,为我想做的每个操作实例化一个存储库是否会更好,以缩短使用寿命,因为如果不是这样,如果我将该类用于许多操作,那么存储库将有许多实体,也许它不需要更多。
所以我在想这样一个解决方案:
public void MyApplicationService()
{
OrderRepository myOrderRepository = new OrderRepository(_options);
Order myOrder = myOrderRepository.GetOrder(1);
myOrder.Update(data);
myOrderRepository.Commit();
myOrderRepository.Dispose();
}
所以每次我都需要做一个新的实例。
因此,总之,我想了解不同的解决方案以及决定存储库使用寿命的优缺点。
谢谢。
存储库的建议使用寿命为一个业务事务。
您的第二个代码补丁在这方面是正确的,但它有一个缺点:在ApplicationService
和OrderRepository
类之间创建了强依赖关系。使用您的代码,您无法隔离这两个类以便分别对它们进行单元测试。此外,无论何时更改OrderRepository
的构造函数,都需要更新ApplicationService
类。如果OrderRepository
需要参数来构造,那么您必须构造它们(这意味着引用它们的类型和基类型(,尽管这是OrderRepository
的实现细节(数据持久性存储访问需要(,而应用程序服务层不需要。
由于这些原因,大多数现代程序开发都依赖于一种称为依赖注入(DI(的模式。使用DI,您可以指定ApplicationService
类依赖于OrderRepository
类的一个实例,或者更好的是OrderRepository
类实现的接口IOrderRepository
。通过在ApplicationService
构造函数中添加一个参数来声明依赖关系:
public interface IOrderRepository : IDisposable
{
Order GetOrder(int id);
void Commit();
}
public class ApplicationService
{
private readonly OrderRepository orderRepository;
public ApplicationService(IOrderRepository orderRepository)
{
this.orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
}
public void Update(int id, string data)
{
Order myOrder = orderRepository.Get(id);
myOrder.Update(data);
orderRepository.Commit();
}
}
现在DI库负责构造OrderRepository
并将实例注入ApplicationService
类中。如果OrderRepository
有自己的依赖项,库将首先解析它们并构建整个对象图,这样您就不必自己这样做了。您只需要告诉您的DI库,您希望每个引用的接口有什么具体的实现。例如C#中的
public IServiceCollection AddServices(IServiceCollection services)
{
return services.AddScoped<IOrderRepository,OrderRepository>();
}
在对代码进行单元测试时,可以将OrderRepository
的实际实现替换为mock对象,例如Mock<IOrderRepository>
或您自己的MockOrderRepository
实现。测试中的代码就是生产中的代码,所有的连接都由DI框架完成。
大多数现代DI库都支持对象生存期管理,包括瞬态(始终解析新对象(、单例(始终重用同一对象(或作用域(每个作用域都有一个实例(。后者用于隔离每个业务事务的对象实例,无论何时启动业务事务,都使用单例ScopeFactory
创建作用域:
public class UpdateOrderUseCase : UseCase
{
private readonly IScopeFactory scopeFactory;
public UpdateOrderUseCase(IScopeFactory scopeFactory) // redacted
public void UpdateOrder(int id, string data)
{
using var scope = scopeFactory.CreateScope();
var orderRepository = scope.GetService<IOrderRepository>();
var order = orderRepository.Get(id);
order.Update(data);
orderRepository.Commit();
// disposing the scope will also dispose the object graph
}
}
当您实现REST服务时,该事务通常对应于一个HTTP请求。现代框架,如asp.net核心,将自动为每个HTTP请求创建作用域,并在稍后的框架内部使用它来解析依赖关系图。这意味着您甚至不必自己处理ScopeFactory。