我不太明白这个[实现领域驱动设计Vaughn,Vernon]实践背后的原因:
使用调解器发布聚合内部状态
解决模型与其客户端之间的紧密耦合问题。
我不太明白这种做法背后试图避免什么:
我不太明白这种做法背后试图避免什么:
- 不在应用层发布聚合?
早在 Web 开发的早期,大多数人都实现了这样的基本应用程序:
public class UserController
{
private readonly MyDbContext context;
public IActionResult GetAll()
{
return Ok(context.Users.ToList());
}
}
这显然很糟糕,因为您可能会暴露业务层逻辑所需的敏感信息,例如密码。人们已经了解到他们需要将“表示模型”(DTO)与数据库模型分开。
随着 DDD 的发展,人们开始编写带有存储库的领域模型来操作它们。所以他们开始实现这样的应用程序(YMMV):
public class UserRepository
{
private readonly MyDbContext context;
public IEnumerable<UserDomain> GetAll()
{
return context.Users.ProjectTo<UserDomain>().ToList();
}
}
public class UserController
{
private readonly UserRepository userRepository;
public IActionResult GetAll()
{
return Ok(userRepository.GetAll().ProjectTo<UserDto>().ToList());
}
}
这是也是错误的,因为:
那么如何实现一个高效的应用呢?您有两个选择:
您可以简单地将 ORM 注入控制器中并使用它来查询数据库。然而,这不是很好,因为您的控制器(在应用程序/表示层中)会因数据库特定代码而变得混乱。
您可以创建一个中介对象,其接口将在应用程序层,而实现将在基础设施层。它的工作方式就像一个存储库,其接口位于领域层,实现位于基础设施层。它将直接返回从持久性存储映射的 DTO,而不是返回域对象。现在,您可以通过调用域服务进行状态更改操作以及调用中介进行查询来实现控制器:
public class UserController
{
private readonly UserService userService;
private readonly UserMediator userMediator;
public IActionResult GetAll()
{
return Ok(userMediator.GetAll());
}
public IActionResult Update(int id, UserDto data)
{
try
{
return Ok(userService.Update(id, data));
}
catch (BusinessException ex) when (ex.Error == UserErrors.NotFound)
{
return NotFound();
}
}
}
public class UserService
{
private readonly MyDbContext context;
public IEnumerable<UserDto> Update(int id, UserDto data)
{
var entity = context.Users.Find(id) ??
throw new BusinessException<UserErrors>(UserErrors.NotFound);
// redacted update of the entity
// business rules go here
context.SaveChanges();
}
}
public class UserMediator
{
private readonly MyDbContext context;
public IEnumerable<UserDto> GetAll()
{
return context.Users.ProjectTo<UserDto>().ToList();
}
}