Domain driven design DDD-使到期失效
目前正潜入DDD,我读了埃里克·埃文斯的大部分蓝皮书。到目前为止相当有趣:) 我已经对一些聚集进行了建模,其中包含过期的实体集合。我提出了一种通用的表达方法:Domain driven design DDD-使到期失效,domain-driven-design,Domain Driven Design,目前正潜入DDD,我读了埃里克·埃文斯的大部分蓝皮书。到目前为止相当有趣:) 我已经对一些聚集进行了建模,其中包含过期的实体集合。我提出了一种通用的表达方法: public class Expirable<T> { public T Value { get; protected set; } public DateTime ValidTill { get; protected set; } public Expirable(T value, DateTime
public class Expirable<T>
{
public T Value { get; protected set; }
public DateTime ValidTill { get; protected set; }
public Expirable(T value, DateTime validTill)
{
Value = value;
ValidTill = validTill;
}
}
可过期的公共类
{
公共T值{get;protected set;}
public DateTime ValidTill{get;protected set;}
公共到期日(T值、日期时间有效期)
{
价值=价值;
ValidTill=ValidTill;
}
}
我很好奇,最好的方法是使一个可过期文件无效(在集合中工作时,将其作废或省略)。到目前为止,我一直在考虑在存储库构造函数中实现这一点,因为在那里可以访问聚合并充当“集合”
我很好奇是否有人想出了解决这个问题的办法,我很高兴听到:)其他方法也很受欢迎
2013年10月1日更新:
这不是Greg Young的CQRS/ES方法的DDD。但是埃文斯的方法是,因为我刚开始写这本书和第一个应用程序。正如格雷格·杨(Greg Young)所说,如果你必须做好桌子,你必须先做几张;) 可能有多种方法来解决这个问题,但我个人会使用规范模式来解决这个问题。假设对象过期是属于域的业务规则,那么除了您编写的类之外,我还需要一个规范。以下是一个例子:
public class NotExpiredSpecification
{
public bool IsSatisfiedBy(Expirable<T> expirableValue)
{
//Return true if not expired; otherwise, false.
}
}
公共类NotExpiredSpecification
{
公共bool符合(到期价值)
{
//如果未过期,则返回true;否则返回false。
}
}
然后,当您的存储库返回聚合列表或对集合执行任何业务操作时,这可以用来将集合限制为未过期的值,这将使您的代码具有表现力,并将业务逻辑保留在域内
要了解有关规范模式的更多信息,请参阅。我已将一个方法添加到我的抽象存储库
InvalidateExpirable
。一个例子是UserRepository
,我在活动用户会话中删除它:InvalidateExpirable(x=>x.sessions,(user,expiredSession)=>user.RemoveSession(expiredSession))代码>
InvalidateExpirable
的签名如下所示:protectedvoid InvalidateExpirable(表达式选择器、动作移除器)
。方法本身使用反射从选择器参数提取选定的属性。该属性名被粘在一个通用HQL查询中,该查询将遍历调用remove lambda的集合user.RemoveSession
将从聚合中删除会话。通过这种方式,我让聚合负责它自己的数据。此外,在RemoveSession
中,还会为将来的案例引发域事件
参见:示例
到目前为止效果相当好,但我必须看看它在应用程序中如何进一步发挥作用。已经阅读了CQRS/ES(Greg Young方法)的DDD,并在MSDN网站上找到了一个关于CQRS/ES的好例子:
在本例中,他们使用命令消息队列对将来的过期消息进行排队,这将在指定时间调用聚合,从聚合中删除/停用可过期的构造。有趣的想法,没有想到!)我已经读过有关规格的章节。这个解决方案的问题是,您必须在内存中加载完整的NotExpired集,这不是很有效。另一方面,它为我提供了一些想法供我尝试。你能详细说明一下吗?规范方法并不意味着您必须加载所有内容,事实上,您应该只加载您需要的内容。该规范只是为了让您能够过滤出正在使用的集合中的过期值。如果有一些值不需要加载到内存中,那么您的存储库将负责过滤,并且在加载存储库时会发生这种情况。这的确是正确的!我后来在编写InvalidateExpirable方法时想到了这一点(见上文)。我可以将该方法中的“查询”部分重构为规范。使域更加优雅和富有表现力。我可能以后再做,但现在已经足够了。查询并不是真正的问题,问题在于何时何地删除不变量(从性能角度看,我想这可能是个问题)。每次启动存储库或存储库中返回数据的每个方法时?(更容易出错)同样,这取决于您的上下文和存储库的结构。但是,在性能方面,您应该只从数据库中加载您需要的内容,不多也不少。确实是一个很好的模式,但是您有没有一个例子来说明在“可过期不变”场景中,T
通常是什么?您将把强制执行不变量的代码放在何处?请参阅下面的注释以获取示例要点。您的示例仅将UserSession
用于T
UserSession
不是DDD意义上的不变量,它是由聚合根强制执行的业务规则。既然你提到了不变量,我只是想知道你是如何用Expirable
实现它们的User
就是T
。因此,User
是维护添加/删除/更新不变量的强制执行(IEnumerable
)的集合。对吗。128“不变量,这是数据更改时必须维护的一致性规则…”