用DDD连接点

jpm*_*m70 5 domain-driven-design ddd-repositories ddd-service

我读过Evans,Nilsson和McCarthy等人,并了解域驱动设计背后的概念和推理; 但是,我发现很难将所有这些放在一个真实世界的应用程序中.缺乏完整的例子让我摸不着头脑.我发现了很多框架和简单的例子,但到目前为止还没有真正演示如何在DDD之后构建真正的业务应用程序.

以典型的订单管理系统为例,以订单取消为例.在我的设计中,我可以看到带有CancelOrder方法的OrderCancellationService,该方法接受订单#和作为参数的原因.然后它必须执行以下"步骤":

  1. 验证当前用户是否具有取消订单所需的权限
  2. 从OrderRepository中检索具有指定顺序#的Order实体
  3. 验证订单是否可能被取消(服务是否应该询问订单的状态以评估规则,或者订单是否具有封装规则的CanCancel属性?)
  4. 通过调用Order.Cancel更新Order实体的状态(原因)
  5. 将更新的订单保留到数据存储
  6. 联系CreditCardService以还原已经处理的任何信用卡费用
  7. 为操作添加审核条目

当然,所有这些都应该在事务中发生,并且不允许任何操作独立发生.我的意思是,如果我取消订单,我必须还原信用卡交易,我无法取消而不执行此步骤.这个,imo,建议更好的封装,但我不希望在我的域对象(Order)中依赖于CreditCardService,所以看起来这是域服务的责任.

我正在寻找有人向我展示代码示例如何/应该"组装".代码背后的思考过程将有助于我为自己连接所有的点.谢谢!

Dmi*_*try 2

您的域服务可能如下所示。请注意,我们希望在实体中保留尽可能多的逻辑,从而保持域服务的精简。另请注意,不直接依赖信用卡或审核员实施 ( DIP )。我们仅依赖于域代码中定义的接口。稍后可以将实现注入到应用程序层中。应用程序层还将负责按编号查找订单,更重要的是,负责在事务中包装“取消”调用(异常时回滚)。

    class OrderCancellationService {

    private readonly ICreditCardGateway _creditCardGateway;
    private readonly IAuditor _auditor;

    public OrderCancellationService(
        ICreditCardGateway creditCardGateway, 
        IAuditor auditor) {
        if (creditCardGateway == null) {
            throw new ArgumentNullException("creditCardGateway");
        }
        if (auditor == null) {
            throw new ArgumentNullException("auditor");
        }
        _creditCardGateway = creditCardGateway;
        _auditor = auditor;
    }

    public void Cancel(Order order) {
        if (order == null) {
            throw new ArgumentNullException("order");
        }
        // get current user through Ambient Context:
        // http://blogs.msdn.com/b/ploeh/archive/2007/07/23/ambientcontext.aspx
        if (!CurrentUser.CanCancelOrders()) {
            throw new InvalidOperationException(
              "Not enough permissions to cancel order. Use 'CanCancelOrders' to check.");
        }
        // try to keep as much domain logic in entities as possible
        if(!order.CanBeCancelled()) {
            throw new ArgumentException(
              "Order can not be cancelled. Use 'CanBeCancelled' to check.");
        }
        order.Cancel();

        // this can throw GatewayException that would be caught by the 
        // 'Cancel' caller and rollback the transaction
        _creditCardGateway.RevertChargesFor(order);

        _auditor.AuditCancellationFor(order);
    }
}
Run Code Online (Sandbox Code Playgroud)