Architecture DDD示例:CargoRepository.Store()是否可以在控制器中使用?

Architecture DDD示例:CargoRepository.Store()是否可以在控制器中使用?,architecture,domain-driven-design,encapsulation,Architecture,Domain Driven Design,Encapsulation,我正在查看来自的优秀NDDDSample源代码,以了解DDD。我对某事感到困惑 CargoRepository有一个查找方法,由BookingService.AssignCargoToRoute和CargoTrackingController调用。搜索: Cargo cargo = CargoRepository.Find(trackingId); CargoRepository还有一个从BookingService.AssignCargoToRoute调用的存储方法: Cargo cargo

我正在查看来自的优秀NDDDSample源代码,以了解DDD。我对某事感到困惑

CargoRepository有一个查找方法,由BookingService.AssignCargoToRoute和CargoTrackingController调用。搜索:

Cargo cargo = CargoRepository.Find(trackingId);
CargoRepository还有一个从BookingService.AssignCargoToRoute调用的存储方法:

Cargo cargo = cargoRepository.Find(trackingId);
if (cargo == null)
{
    throw new ArgumentException("Can't assign itinerary to non-existing cargo " + trackingId);
}

cargo.AssignToRoute(itinerary);
cargoRepository.Store(cargo);
我的困惑是,似乎没有什么可以阻止CargoTrackingController调用CargoRepository.Store,这将绕过BookingService.AssignCargoToRoute中的业务逻辑


为什么DDD中允许这样做?是否应该将存储库分为两部分,一部分用于应用程序/ui/域/服务的读取,另一部分用于域/服务的写入?

好吧,我想这就是CQRS试图实现的目标


当然,在这种情况下,绕过BL是一个坏主意,显然很容易实现,甚至更糟。但是你不能强制执行代码中的所有规则,有些规则只是停留在代码中没有明确声明的约定上。有些坏事可能很难做到,但也不是不可能做到,而且总有很多愚蠢的错误可以犯。编程就是这样:你必须思考你真正在做什么,否则没有任何指导方针,比如DDD,可以帮助你成功。

好吧,我想这就是CQR试图实现的目标


当然,在这种情况下,绕过BL是一个坏主意,显然很容易实现,甚至更糟。但是你不能强制执行代码中的所有规则,有些规则只是停留在代码中没有明确声明的约定上。有些坏事可能很难做到,但也不是不可能做到,而且总有很多愚蠢的错误可以犯。编程就是这样:你必须思考你真正在做什么,否则没有任何指导方针,如DDD,能帮助你成功。

需要将持久性巢穴中的应用程序与服务巢穴分离,以帮助你作为开发人员维护一些易于理解和维护的结构,遵循某种模式并正确使用代码是开发人员的责任


限制开发人员不正确使用它的不是框架,DDD是如何组织应用程序结构的设计模式指南。

需要将应用程序在持久性巢穴和服务巢穴中分离,以帮助开发人员维护一些易于理解和维护的结构,遵循某种模式并正确使用代码是开发人员的责任


它不是限制开发人员不正确使用它的框架,DDD是指导如何组织应用程序结构的设计模式。

在DDD中,服务不是所有业务逻辑的持有者。它们只表示与多个对象交叉相关的领域的动词和动作,因此,如果不打破单一责任原则并造成会混淆实体的紧密耦合,它们就不适合于其中一个实体或聚合根

在您的示例中,Cargo.assigntoroutinerary和BookingService.AssignCargoToRoute似乎是多余的。这两种将货物绑定到路线的方法的存在会造成混乱。您可以保留它们中的任何一个,这取决于您是否认为货物有责任为自己分配一条路线,或者货物是否使用不属于它的功能重载实体


除此之外,控制器直接调用存储库方法是完全合法的。服务不是控制器的单一访问点。

在DDD中,服务不是所有业务逻辑的持有者。它们只表示与多个对象交叉相关的领域的动词和动作,因此,如果不打破单一责任原则并造成会混淆实体的紧密耦合,它们就不适合于其中一个实体或聚合根

在您的示例中,Cargo.assigntoroutinerary和BookingService.AssignCargoToRoute似乎是多余的。这两种将货物绑定到路线的方法的存在会造成混乱。您可以保留它们中的任何一个,这取决于您是否认为货物有责任为自己分配一条路线,或者货物是否使用不属于它的功能重载实体


除此之外,控制器直接调用存储库方法是完全合法的。服务不是控制器的单一访问点。

也许我对DDD的了解太多了,只需要相信常识并采纳指导原则。因此,在这里,我将存储库接口分为两个ICargoRepositoryRead和ICargoRepositoryUpdate,并为控制器提供访问ICargoRepositoryRead接口的权限。我在DDD中读得太多了,只需要相信常识,并采纳指导原则。因此,在这里,我将存储库接口拆分为两个iCargoRespositoryRead和iCargoRespositoryUpdate和
让控制器访问ICargoRepositoryRead接口,我现在明白DDD只是一个设计框架。因此,在这种情况下,我必须假设控制器中的客户机代码希望造成尽可能多的损坏,因此我永远不会给它提供具有更新功能的存储库,即使这个DDD示例does@Gareth:服务巢穴在内部使用,对于客户端使用的外部服务,您可以创建Web服务,例如使用.NET中的WCF,它通常基于您的服务巢穴,在那里您可以定义向客户端公开服务巢穴的哪些方法,并控制权限授权。谢谢,我现在了解到DDD只是一个设计框架。因此,在这种情况下,我必须假设控制器中的客户机代码希望造成尽可能多的损坏,因此我永远不会给它提供具有更新功能的存储库,即使这个DDD示例does@Gareth:服务巢穴在内部使用,对于客户端使用的外部服务,您可以创建Web服务,例如使用.NET中的WCF,它通常基于您的服务巢穴,在那里您可以定义向客户端公开服务巢穴的哪些方法,并控制权限授权。我一直在以错误的方式查看域对象。我原以为我会叫oEntity.Load someId然后oEntity.DoSomething x然后oEntity.Save,但这把坚持的责任放在了严重违反单一责任原则的实体中。实体应该只有作用于自身的方法,并且在单个业务流程中涉及多个实体的情况下创建服务。我现在越来越明白了,谢谢。有趣的是,thanksI一直以错误的方式看待域对象。我原以为我会叫oEntity.Load someId然后oEntity.DoSomething x然后oEntity.Save,但这把坚持的责任放在了严重违反单一责任原则的实体中。实体应该只有作用于自身的方法,并且在单个业务流程中涉及多个实体的情况下创建服务。我现在越来越明白了,谢谢。这东西很有趣,谢谢