關於具體需求,請看前面的博文:DDD領域驅動設計實踐篇之如何提取模型,下面是具體的實體、聚合、值對象的代碼,不想多說什麼是實體、聚合等概念,相信理論的東西你們已經知曉了。本人對DDD表示好奇,沒有在真正項目實踐過,甚至也沒有看過真正的DDD實踐的項目源碼,處於極度糾結狀態,甚至沒法自拔,因此告誡DDD愛好者們,若是要在項目裏面實踐DDD,除非你對實體建模和領域職責很是瞭解(不少時候會糾結一些邏輯放哪裏好,屬於設計問題)以及你的團隊水平都比較高認同DDD,不然請慎重。。。勿噴!html
代碼在後,請先看DEMO結果圖ide
一、聚合的基類,注意,幾乎屬性都是拼音首字母命名,勿噴哈,不要跑題!this
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using DDD.Infrastructure; using DDD.Infrastructure.Domain; namespace DDD.Domain { /// <summary> /// 項目基類 /// </summary> public abstract class ProjectBase : EntityBase, IAggregateRoot { protected ProjectBase() { this.ND = DateTime.Now.Year; this.CJSJ = DateTime.Now; this.WH = new DocumentNumber(); } /// <summary> /// 安排批次 /// </summary> public int APPC { get; set; } /// <summary> /// 項目名稱 /// </summary> public string XMMC { get; set; } /// <summary> /// 項目編號 /// </summary> public string XMBH { get; internal set; } /// <summary> /// 年度 /// </summary> public int ND { get; set; } /// <summary> /// 文號 /// </summary> public DocumentNumber WH { get; set; } /// <summary> /// 建立時間 /// </summary> public DateTime CJSJ { get; set; } /// <summary> /// 下發行政區名稱 /// </summary> public string XFXZQMC { get; set; } /// <summary> /// 下發行政區代碼 /// </summary> public string XFXZQDM { get; set; } /// <summary> /// 行政區名稱 /// </summary> public string XZQMC { get; set; } /// <summary> /// 行政區代碼 /// </summary> public string XZQDM { get; set; } /// <summary> /// 備註 /// </summary> public string BZ { get; set; } /// <summary> /// 指標級別 /// </summary> public IndicatorGrade ZBJB { get; set; } /// <summary> /// 附件id /// </summary> public decimal ATTACHID { get; set; } /// <summary> /// 項目狀態 /// </summary> public ProjectStauts Status { get; set; } /// <summary> /// 業務代碼 /// </summary> protected abstract string BussinessCode { get; } /// <summary> /// 登記 /// </summary> /// <param name="seq"></param> public virtual void Register() { this.XMBH = this.BussinessCode + SeqGeneratr.Generate(); } /// <summary> /// 是否能夠更新或者刪除 /// </summary> /// <returns></returns> public virtual bool CanUpdate() { return this.ZBJB == IndicatorGrade.Country || this.XFXZQDM == this.XZQDM || this.Status == ProjectStauts.Default; } public void Send() { this.Status = ProjectStauts.Sent; } } }
二、聚合1spa
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using DDD.Infrastructure; using DDD.Infrastructure.Domain; namespace DDD.Domain.Indicator { /// <summary> /// 計劃指標 /// </summary> public class PlanIndicator : ProjectBase { public PlanIndicator() { IndicatorArea = new IndicatorArea(); } protected override string BussinessCode { get { return "103101"; } } /// <summary> /// 指標面積 /// </summary> public IndicatorArea IndicatorArea { get; set; } public override IEnumerable<BusinessRule> Validate() { if (this.IndicatorArea.GD > this.IndicatorArea.NYD) { yield return new BusinessRule("IndicatorArea.GD", "耕地面積不能大於農用地面積"); } } public override void Register() { if (this.ZBJB == IndicatorGrade.Country) { this.Send(); } base.Register(); } } }
三、聚合2設計
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using DDD.Infrastructure; using DDD.Infrastructure.Domain; namespace DDD.Domain.Arrange { /// <summary> /// 計劃安排 /// </summary> public class PlanArrange : ProjectBase { public PlanArrange() { JHSY = new IndicatorArea(); SJSY = new IndicatorArea(); } protected override string BussinessCode { get { return "103102"; } } /// <summary> /// 計劃使用面積 /// </summary> public IndicatorArea JHSY { get; set; } /// <summary> /// 實際使用面積 /// </summary> public IndicatorArea SJSY { get; set; } /// <summary> /// 剩餘面積 /// </summary> public IndicatorArea SY { get { return JHSY - SJSY; } } /// <summary> /// 用地類別 /// </summary> public string XMYDLB { get; set; } public override IEnumerable<BusinessRule> Validate() { if (this.JHSY.GD > this.JHSY.NYD) { yield return new BusinessRule("JHSY.GD", "計劃使用中,耕地面積不能大於農用地面積"); } if (this.SJSY.GD > this.SJSY.NYD) { yield return new BusinessRule("SJSY.GD", "實際使用中,耕地面積不能大於農用地面積"); } if (string.IsNullOrEmpty(this.XMYDLB)) { yield return new BusinessRule("XMYDLB", "項目用地類別不容許爲空"); } } } }
四、值對象1htm
using System; using DDD.Infrastructure.Domain; namespace DDD.Domain { /// <summary> /// 文號 /// </summary> public class DocumentNumber : ValueObject<DocumentNumber>, ICloneable { public static readonly string LeftYearChar = "〔"; public static readonly string RightYearChar = "〕"; public DocumentNumber() { } public DocumentNumber(string wh) { try { this.Code = wh.Substring(0, wh.IndexOf(LeftYearChar)); this.Year = wh.Substring(wh.IndexOf(LeftYearChar), wh.IndexOf(RightYearChar) - this.Code.Length + 1); this.Order = wh.Replace(this.Code + this.Year, ""); this.Year = this.Year.Replace(LeftYearChar, "").Replace(RightYearChar, ""); } catch(Exception ex) { throw new InvalidCastException("文號格式不正確", ex); } } /// <summary> /// 發文機關代字 /// </summary> public string Code { get; set; } /// <summary> /// 年份 /// </summary> public string Year { get; set; } private string order; /// <summary> /// 順序號 /// </summary> public string Order { get { if (!string.IsNullOrEmpty(order) && !order.Contains("號")) { order += "號"; } return order; } set { order = value; } } public override string ToString() { if (string.IsNullOrEmpty(Code) && string.IsNullOrEmpty(Year) && string.IsNullOrEmpty(order)) { return string.Empty; } return this.Code + LeftYearChar + Year + RightYearChar + Order; } public static implicit operator DocumentNumber(string wh) { return new DocumentNumber(wh); } public object Clone() { return this.MemberwiseClone(); } } }
五、值對象2對象
using DDD.Infrastructure; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using DDD.Infrastructure.Domain; namespace DDD.Domain { /// <summary> /// 指標面積 /// </summary> public class IndicatorArea : ValueObject<IndicatorArea> { /// <summary> /// 新增建設用地 /// </summary> public decimal XZJSYD { get { return NYD + WLYD; } } /// <summary> /// 農用地 /// </summary> public decimal NYD { get; set; } /// <summary> /// 耕地 /// </summary> public decimal GD { get; set; } /// <summary> /// 未利用地 /// </summary> public decimal WLYD { get; set; } /// <summary> /// 將公頃轉換成畝 /// </summary> /// <returns></returns> public IndicatorArea HectareToMu() { return new IndicatorArea { GD = this.GD * 15, NYD = this.NYD * 15, WLYD = this.WLYD * 15, }; } /// <summary> /// 重載加法運算符 /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> public static IndicatorArea operator +(IndicatorArea a, IndicatorArea b) { return new IndicatorArea { GD = a.GD + b.GD, NYD = a.NYD + b.NYD, WLYD = a.WLYD + b.WLYD, }; } /// <summary> /// 重載減法運算符 /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> public static IndicatorArea operator -(IndicatorArea a, IndicatorArea b) { return new IndicatorArea { GD = a.GD - b.GD, NYD = a.NYD - b.NYD, WLYD = a.WLYD - b.WLYD, }; } public static IndicatorArea Sum(IEnumerable<IndicatorArea> query) { return new IndicatorArea { GD = query.Sum(t => t.GD), NYD = query.Sum(t => t.NYD), WLYD = query.Sum(t => t.WLYD), }; } } }
六、枚舉blog
using System.ComponentModel; namespace DDD.Domain { /// <summary> /// 指標級別 /// </summary> public enum IndicatorGrade { /// <summary> /// 國家 /// </summary> [Description("國家")] Country, /// <summary> /// 省級 /// </summary> [Description("省級")] Province, /// <summary> /// 市級 /// </summary> [Description("市級")] City, /// <summary> /// 縣級 /// </summary> [Description("縣級")] County, } }
using System.ComponentModel; namespace DDD.Domain { /// <summary> /// 項目狀態 /// </summary> public enum ProjectStauts { /// <summary> /// 默認狀態,已登記 /// </summary> Default, /// <summary> /// 已下發 /// </summary> Sent, } }