
對軟體開發方法論有興趣的博友應該發現最近“領域驅動設計”慢慢的被人發現被人實踐起來,園子裡也慢慢有了DDD的學習氣氛和寶貴實戰經驗的分享。其實之前我也癡迷于DDD,為什麼會癡迷于它并不是因為它是所謂的新技術,也不是因為各種對它的炒作,而是我覺得我找到了能解放我們進行企業業務系統開發的方法論。
DDD可以很好的指導我們開發可靠的軟體系統,尤其是現在的企業業務複雜多變的情況下,使用DDD可以很好的随着業務變化不斷的重構現有的領域模型,最為重要的是我覺得DDD是能夠很好的實施靈活價值觀的軟體開發方法論。
閱讀目錄:
- 1.背景介紹
- 2.簡單介紹領域模型模式、活動記錄模式
- 3.活動記錄模式的簡單示例及要點
- 4.總結
如果你想重構、測試你所寫的業務代碼,少不了對代碼進行适當的羅動,如果沒有一個好的結構讓你存放你所提取出來的代碼是比較無奈的。包括現在靈活軟體開發方法論中最重要的TDD方法論更加的依賴代碼的結構是否能夠允許進行重構,如果你的結構是很死闆的,扁平化的其實很難實施TDD,你會發現你所抽象出來的概念無恥容納。
是以我認為DDD是為了解決上述這些問題的一個好的方法,當然前提是你自己實施過之後才有資格去評判它的優劣,而且是客觀公正的。
實施DDD是很費時費力的工程,沒有傳統的開發方法那麼簡單快捷,而且對開發人員的整體要求有了一個新的标準,是以本篇文章将介紹一個可以用來替代DDD模式的另外一個比較好的企業模式“活動記錄模式”。
領域模型模式其實就是領域驅動設計,兩個是一個意思。有興趣的朋友可以進一步學習領域驅動設計,我認為DDD對于一名企業應用開發人員來說是必不可少的一門設計思想,就好比設計模式一樣,它也有着一套模式,用來指導我們進行相關業務場景的設計。
領域模型模式也稱領域驅動設計,對業務模型進行等價的面向對象模組化,無需太多考慮資料存儲的技術細節,但是并不是說完全不考慮如何存儲,如果誰告訴你說完全不需要考慮存儲那是錯誤的,因為你要考慮這個領域模型最終是要如何持久化的,以免你将領域模型建立成一個巨大的蜘蛛網。說不需要考慮領域模型如何持久化其實是說你目前隻需要把握領域模型建立,不去完成持久化設計細節而已,但是這兩個工作往往是互相考慮的。
難道一個不懂得如何存儲關系資料的人能夠建立出能滿足程式員很好的開發的模型嗎。
活動記錄模式是最靠近DDD的模式,它将資料庫中的表中的一行作為自己的對象化字段,然後圍繞着這些字段展開的業務邏輯,将資料字段與業務邏輯都封裝在一個執行個體對象中。
活動記錄模式與表子產品模式不同的是,表子產品模式是一個對象對應着一個資料庫中的表,而活動記錄模式是一個對象對應着一個行記錄,是以稱為活動記錄模式。
此模式最大好處是可以基本上滿足業務不是很複雜的情景下,我倒覺得活動記錄模式在現在的面向SOA架構下能夠更适合企業的業務系統開發團隊。使用領域驅動太過于複雜,不使用又會面臨着業務快速變化的困境,是以活動記錄模式可以考慮試試。
我們來看一個簡單的示例,了解活動記錄模式的開發及要點。
活動記錄模式是使用與資料庫中的表結構一直的方式使用類的,也就是說表中的列就是類的字段,當然也可以在處理業務邏輯時的輔助字段,盡量不包含多餘的字段,這樣可以有效保證幹淨的活動記錄。
1 namespace Business.RecordModels.OrderModel
2 {
3 using System;
4 using System.Collections.Generic;
5
6 /// <summary>
7 /// Order table fields.
8 /// </summary>
9 public partial class OrderFields
10 {
11 /// <summary>
12 /// Order id.
13 /// </summary>
14 public long OId { get; set; }
15
16 /// <summary>
17 /// Order name customer declare.
18 /// </summary>
19 public string OName { get; set; }
20
21 /// <summary>
22 /// Product ids.
23 /// </summary>
24 public List<long> PIds { get; set; }
25
26 /// <summary>
27 /// Order sum price.
28 /// </summary>
29 public float Price { get; set; }
30
31 /// <summary>
32 /// Order distribute status.
33 /// </summary>
34 public int DistributeStatus { get; set; }
35
36 /// <summary>
37 /// Order payment status.
38 /// </summary>
39 public int PaymentStatus { get; set; }
40
41 /// <summary>
42 /// Order signer.
43 /// </summary>
44 public string Signer { get; set; }
45
46 /// <summary>
47 /// Submit datetime.
48 /// </summary>
49 public DateTime SubmitDt { get; set; }
50 }
51 }
定義一個Order活動記錄的字段類,也可以直接将該字段定義在Order類中,但是一般我喜歡獨立出來,因為字段一旦多了看起來實在很累。如果你想将字段直接定義在Order類中我建議你使用部分類來處理,這樣比較幹淨。
字段中的public List<long> PIds { get; set; } 商品ID集合字段是有意聚合到該字段類中的,因為不管是業務處理還是資料持久化都是需要相關連的業務字段的。 (活動記錄模式不要求你很死闆的一個表一個記錄執行個體,隻要你使用你自己的方式能夠讓代碼結構看上去很自然就是很恰當的。)
雖然你直接使用了int類型來描述業務字段,不過你可以使用其他方式讓來該字段在業務進行中不直接使用語言類型而是業務概念。
1 namespace Business.RecordModels.OrderModel
2 {
3 /// <summary>
4 /// Distribute status const.
5 /// </summary>
6 public class DistributeStatusConst
7 {
8 public const int NoDistribute = 1;
9
10 public const int BeginDistribute = 2;
11
12 public const int EndDistribute = 3;
13 }
14 }
配送狀态常量類,定義明确的業務概念的值。
1 namespace Business.RecordModels.OrderModel
2 {
3 /// <summary>
4 /// Payment status const.
5 /// </summary>
6 public class PaymentStatusConst
7 {
8 /// <summary>
9 /// No payment.
10 /// </summary>
11 public const int NoPayment = 1;
12
13 /// <summary>
14 /// End payment.
15 /// </summary>
16 public const int EndPayment = 1;
17 }
18 }
對活動記錄的建立我建議是用工廠來處理,畢竟這裡面包含了很多業務邏輯在裡面的。
1 namespace Business.RecordModels.OrderModel
2 {
3 using Common;
4
5 /// <summary>
6 /// Order class factory.
7 /// </summary>
8 public class OrderFactory
9 {
10 /// <summary>
11 /// Create a order instance.
12 /// </summary>
13 /// <param name="fields">Order fiels instance.</param>
14 /// <returns>Order instance.</returns>
15 public static Order CreateOrder(OrderFields fields)
16 {
17 if (fields.IsNull() || fields.OName.IsNullOrEmpty()
18 || fields.PIds.IsNullOrEmpty() || fields.Price.IsLessThanOrEqual0()) return null;
19
20 fields.DistributeStatus = DistributeStatusConst.NoDistribute;//No distribute.
21 fields.PaymentStatus = PaymentStatusConst.NoPayment;//No payment.
22
23 return new Order(fields);
24 }
25 }
26 }
活動記錄模式不等于沒有DDD那麼好,其實在業務相對不是非常複雜的情況下,活動記錄模式還是相當不錯的,簡單快捷,對一些原子類型的字段處理使用常量就很不錯。
這裡我們使用DistributeStatusConst.NoDistribute、PaymentStatusConst.NoPayment 常量字段來明确的傳達業務概念,而不是非要用枚舉,經驗告訴我有時候枚舉沒有常量友善。
活動記錄對象中包含了該記錄所表達的業務邏輯,這裡的Order将包含該表所表達的業務邏輯處理。
1 namespace Business.RecordModels.OrderModel
2 {
3 using System;
4
5 /// <summary>
6 /// Order table record
7 /// </summary>
8 public partial class Order
9 {
10 /// <summary>
11 /// Order table columns.
12 /// </summary>
13 private OrderFields fields { get; set; }
14
15 /// <summary>
16 /// New a order instance only internal use.
17 /// </summary>
18 /// <param name="fields">Order fields.</param>
19 internal Order(OrderFields fields)
20 {
21 this.fields = fields;
22 }
23
24 /// <summary>
25 /// Calculate order expiration time.
26 /// </summary>
27 /// <returns>DateTime</returns>
28 public DateTime CalculateExpirationTime()
29 {
30 //Here you can use strategy.
31 if (this.fields.PaymentStatus == PaymentStatusConst.NoPayment)//No payment logic
32 {
33 return this.fields.SubmitDt.AddDays(1);
34 }
35 else if (this.fields.DistributeStatus == DistributeStatusConst.NoDistribute)//No payment logic
36 {
37 return this.fields.SubmitDt.AddDays(30);
38 }
39
40 return this.fields.SubmitDt.AddDays(3);
41 }
42 }
43 }
這裡我有一個簡單的計算目前訂單到期時間的方法(CalculateExpirationTime),在方法内部有一些業務邏輯,而該業務邏輯和目前執行個體一起存在。
通過使用活動記錄模式可以很好的将字段與業務方法有效的集合起來,這樣會使得業務邏輯處理比較有條理性,也便于測試和重構。
這裡需要強調的是活動記錄模式是業務層和資料層共用的模式,當時這裡我們所講的是面向業務層的,也就是說你資料層可以使用任何方式來和活動記錄模式整合,現在比較流行ORM了,如果你對性能有要求你可以使用手工處理,建議使用表入口模式來結合,因為資料層沒有什麼邏輯,如果你的資料層有相關的邏輯我像也不會出現最後的資料源上,而是應該在資料适配層上處理掉,如:緩存、填補字段等。
很難在一篇文章中說明所有問題,活動記錄模式如果是用在讀寫分離大的架構中的寫端時必須需要“工作單元”模式來協調多“記錄”之間的事務性。但是如果你在查詢端使用活動記錄模式,那麼大部分情況下是不需要事務性的,當然查詢端我覺得使用事物腳本模式比較直覺點,因為業務邏輯也不會有多少。
還是那句話,本篇文章隻是分享點自己學習過程中和工作過程總結的經驗,僅供參考。其實企業應用架構是一個看似簡單其實很複雜的方向,希望與各位一起學習一同進步,謝謝。
作者:王清培
出處:http://www.cnblogs.com/wangiqngpei557/
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面