我们正在尝试CQRS.我们有一个验证情况,其中CustomerService(域服务)需要知道客户是否存在.客户的电子邮件地址是唯一的.我们的客户存储库(通用存储库)仅具有Get(id)和Add(customer).CustomerService应该如何确定客户是否存在?
仅供讨论,对我而言,似乎有两种不同的术语实际上是在说同一件事.这两种设计方法之间是否有任何明显的差异?
从初学者到高级,您可以找到关于领域驱动设计的所有信息.
在这个问题中有人回答 "你永远不会让域对象实现自己调用服务!".这个陈述是DDD的一个严格的快速规则,还是取决于您自己的应用程序和架构?
举例:
举个例子,我们假设我们UserImage的模型中有一个对象,它由用户从上传的图像中填充.然后我们假设我们可以将此图像提交给可识别拇指打印的第三方服务,Guid如果找到匹配则返回.
public IThumbPrintService {
Guid FindMatch(Bitmap image);
}
public class UserImage {
public Bitmap Image {get; set;}
public Guid ThumbPrintId {get; set;}
public bool FindThumbPrintMatch() {
// Would you call the service from here?
ThumbPrintId = _thumbPrintService.FindMatch(this.Image);
return ! ThumbPrintId.CompareTo(Guid.Empty);
}
}
public class RoboCopUserImageService : IUserImageService {
// Or move the call to a service method
// since it depends on calling a separate service interface
public bool FindThumbPrintMatch(UserImage …Run Code Online (Sandbox Code Playgroud) 经过几年跟随我工作地点"建筑师"传下来的不良做法并认为必须有更好的方法,我最近一直在阅读TDD和DDD,我认为原则和实践将是一个非常适合我们编写的软件的复杂性.
但是,我见过的许多TDD示例都在域对象上调用一个方法,然后测试对象的属性以确保正确执行行为.
另一方面,业内几位受人尊敬的人(Greg Young最着名的是关于CQRS的讨论)主张通过删除所有"getters"来完全封装每个域对象.
因此,我的问题是:如果禁止检索域状态,如何测试域对象的功能?
我相信我缺少一些基本的东西,所以请随时称我为白痴并启发我 - 任何指导都将非常感谢.
关于DDD,我可能有一个愚蠢的问题:DDD是否存在任何不正常的问题?我的意思是,除了在没有必要或需要时使用它.(例如小/不复杂的项目)
谢谢
背景:为了我自己的清晰度/自我教育,我试图使用TDD + DDD实现一个简单的订单输入应用程序.我的主要目标是通过分离问题来保持架构的清洁.
我有四层(现在)......
具有CustomerRepository类的Persistence/DAL,可以对"聚合根",客户及其相关订单和OrderItem执行GetById,Save,操作.为了让"穷人的依赖注入"
包含"业务实体"类的域/ BLL层,执行细粒度操作以帮助创建新订单,根据订单大小和客户位置应用税,折扣,装运逻辑.
应用程序Facade(应用程序服务/编排)包含大块,粗粒度的类来编排"业务实体"并减少与表示(可能是WebServices层)的聊天.
表示层
此外,我想在关键层之间传递POCO DTO ...特别是在Persistence => Domain层和ApplicationFacade => Presentation层之间.因此,我有CustomerDto,OrderDto,OrderItemDto以及在共享包中定义的适当关系.
我想使用Constructor Injection将ICustomerRepository的实现注入到Customer"业务实体"类中,然后在"业务实体"上调用Customer.Save()以启动创建/更新过程,最终调用Save方法CustomerRepository.毕竟,客户是"聚合根"并拥有保存所需的所有信息......它也是注入的CustomerRepository的"守护者".
问题: 这是我遇到麻烦的地方.我想保持Domain/BLL Layer尽可能纯,并避免将其耦合到任何第三方框架和API,但 Customer.Save()方法需要将Customer"聚合根"及其所有Orders和OrderItems转换为他们的DTO版本用于传输到注入的持久层CustomerRepository ...这是Automapper的工作.
问题是......如果我不把Automapper在域/ BLL层,我真的不知道哪里应该去.
将它放在ApplicationFacade中感觉不对,即使它的工作是编排.
把它放在Domain/BLL层中肯定是不对的,因为我想让它保持原始状态.
因此,我觉得我已经错过了一些东西......我正在接近这一点,因为他们对工作部分应该如何共同完成这项任务有着根本的误解.有什么建议?(请保持温和,我对这一切都是新手,对SO来说是新手.如果我需要展示一些我到目前为止的代码,请告诉我.)
我正在考虑使用规范模式进行验证.困难的是如何告诉用户为什么某些规范不满意.如果Specification.IsSatisfiedBy()不仅会返回一个bool值,而且还会失败的原因怎么办?它看起来像这样:
interface ISpecification<T>
{
CheckResult IsSatisfiedBy(T candidate);
}
Run Code Online (Sandbox Code Playgroud)
在哪里CheckResult:
class CheckResult
{
public bool IsSatisfied { get; }
public string FailureReason { get; }
}
Run Code Online (Sandbox Code Playgroud)
在Fowler&Evans的工作中,有一个部分满足规范的概念,其目的是提供解释究竟不满足的内容.但是在该文档中,它被实现为附加方法remainderUnsatisfiedBy,它返回候选者未完成的规范.
所以问题是:当使用规范进行验证时,如何向用户提供不满足给定规范的反馈?我上面介绍的解决方案是否合适?