DDD:订单管理 之 如何组织代码

背景

系统开发最难的是职责的合理分配,或者叫:“如何合理的组织代码”,今天说一个关于这方面问题的示例,希望大家多批评。

示例背景

参考数据字典

需求

  1. OrderCode必须唯一。
  2. Total = Sum(Subtotal)。
  3. 订单有三种状态:【未提交】、【待审核】和【已审核】,合理的状态迁移有:【未提交】----》【待审核】和【待审核】----》【已审核】,只有处于【未提交】状态的订单能修改。
  4. 订单和订单项中的状态必须合法,规则自己定义。

示例实现

项目结构

  • Application:应用层,负责领域逻辑的封装。主要角色:ApplicationService、CommandHandler。
  • Boostrap:启动管理层,负责启动过程管理,如:注册Ioc、初始化配置。主要角色:BootstrapListener。
  • Commands:命令层,是一个契约层。主要角色:Comamnd、DTO。
  • Controllers:控制器层,边界层。主要角色:Controller。
  • Domain:领域层,负责领域逻辑的组织。主要角色:Aggregate、Entity、ValueObject、Factory、DomainService、IRepository、IUnitOfWork。
  • Events:事件层,是一个契约层,跨聚合流程可以采用。主要角色:Event。
  • EventSubscribers:事件监听层。主要角色:EventSubscriber。
  • Infrastructure:基础设施层。主要角色:Repository、QueryService、UnitOfWork。
  • Query:查询层,为UI的查询提供服务,主要角色:QueryService。

项目整体采用简单的CQRS架构,Command端采用DDD组织,Query直接从数据库返回dynamic类型。Event可以用来处理跨聚合通信,也可以用来处理长事务或离线事务。

重点介绍的领域层

采用状态模式处理状态迁移。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Happy.Example.Domain.TestOrders
 8 {
 9     public interface ITestOrderState
10     {
11         void AddTestOrderDetail(TestOrderDetail testOrderDetail);
12 
13         void UpdateTestOrderDetail(Guid testOrderDetailId,decimal subtotal);
14 
15         void RemoveTestOrderDetail(Guid testOrderDetailId);
16 
17         void Commit();
18 
19         void Verify();
20 
21         string Status { get; }
22 
23         TestOrder TestOrder { set; }
24     }
25 }
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Happy.Example.Domain.TestOrders
 8 {
 9     public partial class TestOrder
10     {
11         private abstract class TestOrderState : ITestOrderState
12         {
13             public virtual void AddTestOrderDetail(TestOrderDetail testOrderDetail)
14             {
15                 this.ThrowInvalidOperationException();
16             }
17 
18             public virtual void UpdateTestOrderDetail(Guid testOrderDetailId,decimal subtotal)
19             {
20                 this.ThrowInvalidOperationException();
21             }
22 
23             public virtual void RemoveTestOrderDetail(Guid testOrderDetailId)
24             {
25                 this.ThrowInvalidOperationException();
26             }
27 
28             public virtual void Commit()
29             {
30                 this.ThrowInvalidOperationException();
31             }
32 
33             public virtual void Verify()
34             {
35                 this.ThrowInvalidOperationException();
36             }
37 
38             public abstract string Status { get; }
39 
40             public TestOrder TestOrder { protected get; set; }
41 
42             private void ThrowInvalidOperationException()
43             {
44                 throw new InvalidOperationException(string.Format("处于【{0}】的订单不能执行此操作!",this.Status));
45             }
46         }
47     }
48 }
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Happy.Example.Domain.TestOrders
 8 {
 9     public partial class TestOrder
10     {
11         private sealed class UnCommitted : TestOrderState
12         {
13             internal static readonly string UnCommittedStatus = "未提交";
14 
15             public override void AddTestOrderDetail(TestOrderDetail testOrderDetail)
16             {
17                 this.TestOrder.DoAddTestOrderDetail(testOrderDetail);
18             }
19 
20             public override void UpdateTestOrderDetail(Guid testOrderDetailId,decimal subtotal)
21             {
22                 this.TestOrder.DoUpdateTestOrderDetail(testOrderDetailId,subtotal);
23             }
24 
25             public override void RemoveTestOrderDetail(Guid testOrderDetailId)
26             {
27                 this.TestOrder.DoRemoveTestOrderDetail(testOrderDetailId);
28             }
29 
30             public override void Commit()
31             {
32                 this.TestOrder.DoCommit();
33             }
34 
35             public override string Status
36             {
37                 get { return UnCommittedStatus; }
38             }
39         }
40     }
41 }

采用封装集合手法处理Total的同步问题。

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Threading.Tasks;
  6 
  7 using Happy.Domain;
  8 using Happy.Domain.Tree;
  9 using Happy.Infrastructure.ExtentionMethods;
 10 using Happy.Example.Events.TestOrders;
 11 
 12 namespace Happy.Example.Domain.TestOrders
 13 {
 14     public partial class TestOrder : AggregateRoot<Guid>
 15     {
 16         private ITestOrderState _orderState;
 17 
 18         protected TestOrder() { }
 19 
 20         public TestOrder(string orderCode,string customer)
 21         {
 22             orderCode.MustNotNullAndNotWhiteSpace("orderCode");
 23             customer.MustNotNullAndNotWhiteSpace("customer");
 24 
 25             this.Id = Guid.NewGuid();
 26             this.OrderCode = orderCode;
 27             this.Customer = customer;
 28             this.OrderState = TestOrderStateFactory.CreateUnCommittedTestOrderState(this);
 29             this.TestOrderDetails = new List<TestOrderDetail>();
 30         }
 31 
 32         public virtual System.String OrderCode { get; protected set; }
 33         public virtual System.String Customer { get; protected set; }
 34         public virtual System.Decimal Total { get; protected set; }
 35         public virtual System.String Status { get; protected set; }
 36         public virtual ICollection<TestOrderDetail> TestOrderDetails { get; protected set; }
 37 
 38         private ITestOrderState OrderState
 39         {
 40             get
 41             {
 42                 if (_orderState == null)
 43                 {
 44                     _orderState = TestOrderStateFactory.Create(this,this.Status);
 45                 }
 46 
 47                 return _orderState;
 48             }
 49             set
 50             {
 51                 _orderState = value;
 52                 this.Status = value.Status;
 53             }
 54         }
 55 
 56         public void AddTestOrderDetail(TestOrderDetail testOrderDetail)
 57         {
 58             this.OrderState.AddTestOrderDetail(testOrderDetail);
 59         }
 60 
 61         public void UpdateTestOrderDetail(Guid testOrderDetailId,decimal subtotal)
 62         {
 63             this.OrderState.UpdateTestOrderDetail(testOrderDetailId,subtotal);
 64         }
 65 
 66         public void RemoveTestOrderDetail(Guid testOrderDetailId)
 67         {
 68             this.OrderState.RemoveTestOrderDetail(testOrderDetailId);
 69         }
 70 
 71         public void Commit()
 72         {
 73             this.OrderState.Commit();
 74         }
 75 
 76         public void Verify()
 77         {
 78             this.OrderState.Verify();
 79         }
 80 
 81         private void DoAddTestOrderDetail(TestOrderDetail testOrderDetail)
 82         {
 83             this.TestOrderDetails.Add(testOrderDetail);
 84 
 85             this.Total += testOrderDetail.Subtotal;
 86         }
 87 
 88         private void DoUpdateTestOrderDetail(Guid testOrderDetailId,decimal subtotal)
 89         {
 90             var testOrderDetail = this.TestOrderDetails.First(x => x.Id == testOrderDetailId);
 91 
 92             this.Total -= testOrderDetail.Subtotal;
 93             testOrderDetail.Subtotal = subtotal;
 94             this.Total += testOrderDetail.Subtotal;
 95         }
 96 
 97         private void DoRemoveTestOrderDetail(Guid testOrderDetailId)
 98         {
 99             var testOrderDetail = this.TestOrderDetails.First(x => x.Id == testOrderDetailId);
100 
101             this.TestOrderDetails.Remove(testOrderDetail);
102             this.Total -= testOrderDetail.Subtotal;
103         }
104 
105         private void DoCommit()
106         {
107             this.OrderState = TestOrderStateFactory.CreatePendingVerificationTestOrderState(this);
108         }
109 
110         private void DoVerify()
111         {
112             this.OrderState = TestOrderStateFactory.CreateVerifiedTestOrderState(this);
113 
114             this.PublishEvent(new TestOrderVerified());
115         }
116     }
117 }

效果图

背景

写这个简单的Demo过程,遇到了很多小的决策,这篇文章就看做一个开头吧,后边重点介绍每个决策点,在一篇文章中真的很难说完,喜欢看代码的朋友,先去https://happy.codeplex.com/下载。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结