閱讀目錄:數據庫
一直都在談論面向對象開發,可是開發企業應用系統時,使用面向對象開發最大的問題就是在於,多個對象之間的互操做須要涉及數據庫操做。兩個業務邏輯對象彼此之間須要互相調用,若是之間的互相操做是在一個業務事務範圍內的,很容易完成,可是若是本次業務邏輯操做涉及到多個業務對象一塊兒協做完成時問題就來了。架構
在以往,咱們使用過程式的代碼(事務腳本模式),將全部與本次業務事務範圍內相關的全部邏輯都寫在一個大的代碼中,就算你適當的提取重複代碼,效果也不大,由於你永遠都擺脫不了誇多個對象互相操做的困境。如何確認你是否在這個困境中,你只要看你的全部事務操做的入口都只有一個業務方法。好比當你添加一個訂單的時候,你同時將訂單跟隨的商品都一塊兒在「添加訂單」的方法中處理的,而不是在另一個「添加訂單商品」的方法中,這兩個方法位於不一樣的表模塊類中。框架
本章將介紹一個模式,此模式專門用來在開發企業應用系統時,協調多個業務對象在一個業務事務範圍內,保證一個完整的事務。工具
其實開發應用系統與開發某個框架或者組件之間的最大區別就是須要考慮數據的持久化,而持久化的邏輯也是和業務邏輯息息相關的,某個方法的最後動做就有多是添加一行數據或者更新一個字段。而非應用系統的代碼每每在最後的時候纔去統一刷新最終的持久化文件,並且此類程序不多存在事務性數據操做。就算有,使用內存事務處理也是比較簡單的,不須要考慮那麼多的服務端的事情。佈局
我以前也寫過不少組件、框架,雖然談不上什麼複雜的東西,可是給個人經驗和感悟就是,如何將其細緻的設計粒度用在企業應用系統中,如何進行復雜而細緻的OO設計開發。其實,若是咱們不可以打破過程式代碼的格局,那麼看再多的OO知識也是愛莫能助,反而會讓你產生不少負面的情緒(由於我有過這個經歷)。this
其實咱們仍是缺乏正確的方法而已,本文中UnitOfWork模式將幫助咱們走出過程式的業務邏輯,走向起碼的面向對象開發。有了UnitOfWork你能夠隨意使用Table module 、Activa Record、Domin Driven 模式,並且你能夠根據本身的項目須要將其在大的佈局上進行SOA劃分(CQRS),讓各個模式在各自適合的場景中發揮極致。spa
這裏咱們依然使用簡單的訂單購物業務做爲示例來說,畢竟你們都懂得這部分的的業務概念。本實例業務層使用Active Record模式。設計
1 namespace OrderManager.Business 2 { 3 using System.Collections.Generic; 4 5 public partial class Order 6 { 7 public long OId { get; set; } 8 9 public List<OrderProducts> Products { get; set; } 10 } 11 }
Order活動記錄對象的字段部分。日誌
1 namespace OrderManager.Business 2 { 3 public partial class Order 4 { 5 public bool CheckOrder() 6 { 7 //執行部分業務驗證工做 8 if (this.OId <= 0) return false; 9 10 return true; 11 } 12 } 13 }
Order活動記錄對象主體,純粹爲了演示而用,包含了一個簡單的判斷業務邏輯。code
1 namespace OrderManager.Business 2 { 3 public partial class OrderProducts 4 { 5 public long OrderId { get; set; } 6 7 public long PId { get; set; } 8 9 public float Price { get; set; } 10 } 11 }
訂單商品部分字段。
1 namespace OrderManager.Business 2 { 3 public partial class OrderProducts 4 { 5 public bool CheckProducts() 6 { 7 //執行部分業務驗證工做 8 if (this.OrderId <= 0) return false; 9 10 return true; 11 } 12 } 13 }
每個商品都包含了本身的邏輯驗證。
咱們接着看一下應用層入口方法是如何協調兩個活動記錄對象之間的業務操做和數據存儲的。
1 namespace OrderManager 2 { 3 using OrderManager.Business; 4 using OrderManager.DataSource; 5 6 public class OrderManagerController : ControllerBase 7 { 8 public bool AddOrder(Order order) 9 { 10 using (UnitOfWork unitOfWork = new UnitOfWork()) 11 { 12 order.CheckOrder();//執行業務檢查 13 14 order.Products.ForEach(item => 15 { 16 item.CheckProducts();//執行每一個活動記錄對象的業務檢查,這裏也可使用表模塊來處理。 17 }); 18 19 OrderGateway orderGateway = new OrderGateway(unitOfWork); 20 var orderDbResult = orderGateway.AddOrder(order);//第一個數據庫表操做 21 22 OrderProductsGateway productGateway = new OrderProductsGateway(unitOfWork); 23 var productDbResult = productGateway.AddOrderProducts(order.Products);//第二個數據庫表操做 24 25 if (orderDbResult && productDbResult) 26 { 27 if (unitOfWork.Commit()) 28 { 29 this.SendOrderIntegrationMssage(order);//發送成功集成訂單消息 30 31 return true; 32 } 33 34 this.PushOrderProcessQueue(order);//將本次訂單發送處處理隊列中 35 return false; 36 } 37 38 this.LogBusinessException(order);//記錄一個業務處理異常LOG,以備排查問題。 39 return false; 40 } 41 } 42 } 43 }
爲了簡單演示示例,我直接使用實例化的方式來構造數據訪問對象,實際使用時可使用IOC工具來動態注入。
咱們接着看一下數據層代碼,數據層我使用表入口模式。
1 namespace OrderManager.DataSource 2 { 3 public abstract class GatewayBase 4 { 5 protected UnitOfWork UnitOfWork { get; private set; } 6 7 public GatewayBase(UnitOfWork unit) 8 { 9 this.UnitOfWork = unit; 10 } 11 12 public bool Commit() 13 { 14 return this.UnitOfWork.Commit(); 15 } 16 17 public void Rollback() 18 { 19 this.UnitOfWork.Rollback(); 20 } 21 } 22 }
這是一個表入口基類。
1 namespace OrderManager.DataSource 2 { 3 using OrderManager.Business; 4 5 public class OrderGateway : GatewayBase 6 { 7 public OrderGateway(UnitOfWork unit) : base(unit) { } 8 9 public bool AddOrder(Order order) 10 { 11 //這裏可使用你所熟悉的拼接SQL的方式直接操做數據庫,而不須要ORM。 12 return true; 13 } 14 } 15 }
1 namespace OrderManager.DataSource 2 { 3 using OrderManager.Business; 4 using System.Collections.Generic; 5 6 public class OrderProductsGateway : GatewayBase 7 { 8 public OrderProductsGateway(UnitOfWork unit) : base(unit) { } 9 10 public bool AddOrderProducts(List<OrderProducts> products) 11 { 12 //這裏可使用你所熟悉的拼接SQL的方式直接操做數據庫,而不須要ORM。 13 return true; 14 } 15 } 16 }
這是兩個表入口對象,其實這部分代碼是你們都比較熟悉的,因此我這裏省略了,你能夠直接拼接SQL語句來插入數據庫。
1 namespace OrderManager.DataSource 2 { 3 using System; 4 5 public class UnitOfWork : IDisposable 6 { 7 public void Dispose() 8 { 9 throw new NotImplementedException(); 10 } 11 12 public bool Commit() 13 { 14 return true; 15 } 16 17 public void Rollback() 18 { 19 // 20 } 21 } 22 }
UnitOfWrok對象其實就是對數據庫對象的System.Data.Common.DbConnection對象的封裝,這裏你可使用你熟悉的方式來構造這個數據庫鏈接對象和開啓事務。
其實值得咱們去欣賞的是應用控制器中的代碼,在這裏很協調的處理各個邏輯,最後記錄下一些必要的日誌和發送一些集成消息。你是否是發現你徹底能夠不使用DDD也能夠處理部分業務系統了。
活動記錄模式+表入口模式+工做單元模式,其實我以爲能夠很好的處理中小型業務邏輯,隨着如今SOA化架構,不多再有多大的項目在一個解決方案裏面。
最後仍是那句話,提供一個參考資料,若是有興趣能夠進一步交流具體的設計,因爲時間關係文章就到這裏了,謝謝你們。