也许是一个人为的,但例如,我有一个命令,我想将用户密码重置他的电子邮件地址和一个命令,我想更新用户的最后一个 登录日期
public class ResetPasswordCommandHandler : CommandHandler<ResetPasswordCommand>
{
public override void Execute(ResetPasswordCommand command)
{
**// duplication here**
var user = from c in db.Users
where c.EmailAddress = command.EmailAddress
select c;
user.EmailAddress = command.EmailAddress;
...
db.Save();
}
}
public class UpdateLastLoginCommandHandler : CommandHandler<UpdateLastLoginCommand>
{
public override void Execute(UpdateLastLoginCommand command)
{
**// duplication here**
var user = from c in db.Users
where c.EmailAddress = command.EmailAddress
select c;
user.LastLogin = DateTime.Now;
...
db.Save();
}
}
在两个命令中,我都根据用户的电子邮件地址检索。现在,如果我想在查询数据库之前对UI输入进行修剪,则必须在两个地方更改此信息。 我当然可以创建一个用户重新设备,例如,它可以使用一个方法getuserbyemailAddress,然后插入iuserRepository将其插入我的CommandLandlers的构造函数中。但是,这最终不会用保存,getByid,getByusername等创建一个“上帝存储库”? 如果我创建一个存储库,为什么要创建单独的查询对象?
如何保持该代码干燥?
当您不重构您的命令处理程序中,将多个接口的处理程序:
public class UserCommandHandler : CommandHandlerBase,
IHandle<ResetPasswordCommand>,
IHandle<UpdateLastLoginCommand>
{
public void Execute(ResetPasswordCommand command)
{
var user = GetUserByEmail(command.EmailAddress);
user.EmailAddress = command.EmailAddress;
...
db.Save();
}
public void Execute(UpdateLastLoginCommand command)
{
var user = GetUserByEmail(command.EmailAddress);
user.LastLogin = DateTime.Now;
...
db.Save();
}
private User GetUserByEmail(string email) {
return (from c in db.Users
where c.EmailAddress = command.EmailAddress
select c).FirstOrDefault();
}
}
这种方式,您可以在命令处理程序中重构私人辅助方法,命令处理程序可以处理类似的命令,并减少代码重复。 您也不需要“上帝”存储库。
个人,我宁愿让私人
GetUserByEmail
助手作为一个单独的查询类,我通过构造函数注入
db
上下文,因此
GetUserByEmail
User
。
希望这帮助
它不会创建一个上帝的存储库。它将是一个适当的存储库,其中具有命令用例使用的方法。但这意味着您使用的是正确的存储库模式,这意味着没有易用或EF暴露。请记住,域存储库具有仅由域用例所需的“查询”方法,而存储库仅处理域聚合根(整个域对象)。
您当前的方法是在您的应用程序服务中使用EF(最后一个DAO),这意味着应用程序层以及域层也可能与EF耦合。您的高级服务(命令处理程序是最终的服务,实现用例)不应进行查询,因为从他们的角度来看,没有RDBMS,即他们对查询不了解。
如果您的应用程序足够简单或您知道将来不会发生太大变化,那么您可以采取直接使用EF的快捷方式,但是如果您决定以这种方式简化事物,那么您就不需要CQR和一个基于消息的体系结构我知道它看起来像是代码重复,我知道您似乎要违背干燥的原理,但是我可以向您保证使用行为中的共享服务存储库代码绝不是一个好主意。问题之一是,每种行为实际上都需要通过电子邮件调用对Getuser的实现略有不同。一个我的要求全名可能没有。通过共享此代码,您可以有效地紧密耦合两个呼叫。现在,一种行为可能需要返回额外的数据,但是现在,当您在其他实现时,当您将其他实施调用此“共享服务”时,您就会致电,它具有不需要的所有额外数据的开销。
如果您在执行存储库调用时要共享代码,请使用所谓的规范模式和 /或策略模式。您不会从上面的示例中遇到任何令人讨厌的紧密耦合问题,并且作为奖励,您的代码会更好地读取,因为意图是脱颖而出而不是实现。
在您的命令上没有实际重复,您要做的就是将DB查询逻辑封装到存储库方法中,并在两个命令处理程序中调用该方法,例如: