1. 程式人生 > >領域驅動設計,讓程序員心中有碼(七)

領域驅動設計,讓程序員心中有碼(七)

流程 處理機 解耦 驅動 容易 優點 含義 低耦合 程序

領域驅動設計- 讓程序員心中有碼(七)

-設計原則和設計模式,互聯網開發者們共同的追求

前言

  多年來,筆者一直從事傳統軟件企業的軟件開發和項目管理工作。筆者發現在眾多的傳統軟件企業中,評判優秀開發者的標準往往是技能的熟練程度,基本上都是以梭代碼的速度論英雄。有人評價說,這種開發可以稱之為cv編程,即ctrl+c和ctrl+v編程為主。這種開發往往對開發者的技能要求並沒有想象中的那麽高,由於工時和合同的限制,不得不壓縮開發時間,通過靠密集的勞動力資源、較高的工作強度來完成項目的開發。這種模式,通過簡單的復用歷史代碼,可以更快的輸出結果,對於中小型企業和一些外包企業來說,也意味著更快的項目完成速度、而越快做完項目,也意味著可以越快收回合同款,盡快開始下一個項目。

  然而,也必須承認,在這種模式下,代碼的質量取決於項目管理者對於技術和代碼的把握能力,如果攤上不懂技術的項目管理者以及對於代碼質量沒有要求的研發人員,可能最終輸出的代碼,將成為一團亂麻,只能在一個個項目中無窮次的積累,直到遇到一群優秀的開發人員費勁心力把體系重構為止。

  而當今互聯網時代下,面向互聯網的應用開發,不再追求短期成效,更在乎長期技術的沈澱,這個過程中,也對開發者提出了更高的要求。互聯網行業的開發者,不僅僅要求代碼梭得快,還在乎編寫代碼編寫的質量,誰能編寫出更加優美的代碼,往往也更容易受人歡迎。於是,作為優美代碼代名詞的SOLID設計原則和很多種設計模式實際上成為了非常基礎的一種能力,甚至於許多資深的開發者,經常會樂此不疲的進行各種代碼的重構,也是期待能夠更好的將設計模式揉碎了,應用到代碼中,更好的實現高內聚、低耦合的目標。

《head first》中的工廠模式

   在著名小紅書《Head First》一書中,描述了多種設計模式,這些由資深IT技術大牛們抽象化出來的最佳代碼實踐,初讀起來也許簡單明了,但是細細品味起來,卻意味深長。

   在傳統軟件開發實踐工程中,往往會下意識的使用New關鍵字產生對象實例。通過這種方式進行代碼的編寫,固然會帶來代碼上的開發速度,但是同樣也會給對象的生成帶來一些問題。例如,對象的構造,往往附帶了許多復雜的條件:如需要進行一些初始值的設置,如需要初始化與之相關的子類,或者需要預先執行許多初始化方法,那麽就可能意味著代碼的構造中會產生一系列復雜、與主流程無關的代碼。如何讓輕松方便的構造代碼、而不去關心具體的實現細節呢?

  工廠模式成為解決問題的方案,通過工廠模式,適當的創建接口,將代碼中的具體過程進行屏蔽,從而提高了代碼的靈活性。又分為靜態工廠、簡單工廠模式、工廠方法模式、抽象工廠模式等多種不同的模式。例如,我們可能會編寫一段下面的代碼。

 1 public abstract class FactoryPizzaStore
 2 {
 3         public Pizza OrderPizza(string type)
 4         {
 5 
 6             Pizza pizza = CreatePizza(type);
 7             return pizza;
 8         }
 9         public abstract Pizza CreatePizza(string type);
10 }

  我們可以看到,這只是一段最普通的工廠代碼,定義了一個抽象對象,如果需要實現成員,只需繼承此對象,並重載方法,這種方法可以非常便捷的將內部對象的創建過程進行封裝,實現了代碼內聚性的顯著提高。

領域驅動中的工廠模式和倉儲模式

在領域驅動中,將工廠模式引入其中,讓其產生了不同的含義。在上一章,我們了解到,隨著軟件系統復雜性的顯著提高,維護模型實例的生命周期變成了一件非常困難的事情,因此通過引入一個聚合Aggregate對象,可以有效的將復雜的模型復雜的生命周期的各個階段進行封裝,通過一系列固定的規則,實現了對數據更加的控制。而這種控制,則是通過工廠模式和倉儲模式來實現的。這兩種模式,實現了對Aggregate對象的操作,實現了復雜的生命周期轉換復雜性的良好封裝。

領域工廠模式

  一個復雜的軟件系統,往往如同生產一臺汽車,它由許多個不同的部件組成,每個部件間通過一系列復雜的協同運動來實現整體的職能。對於用戶而言,汽車是如何裝配的,並不是他所關心的問題,他只在乎如何駕駛這輛汽車。這意味著,裝配過程,應該與對象要執行的工作分開。軟件系統同樣如此,我們設計了一個復雜的聚合對象,這個對象內部有大量的實體或者值對象。如果開發者需要使用這個對象,必須按照一系列規則來進行操作。

在這個聚合對象的生命周期中,如果將創建的過程按照調用的場景,分拆到不同的環節中,可能使代碼的耦合性急劇提高,帶來的將是後期高昂的更改成本。

  在領域驅動設計中,復雜對象的創建過程往往是領域層的核心職能,但是,對於這個復雜對象創建過程,又顯然不能有簡單的Service對象來實現,因此,需要引入工廠模式。封裝創建復雜對象或聚合對象

的全部規則,並通過提供相關接口、創建對象的抽象視圖,讓創建的過程符合規則。

  在領域工廠模式中,往往有以下要求:

1、創建過程的原子性、滿足創建所需的所有規則。由於我們引入工廠的目的,是為了將復雜的常見過程進行封裝,因此我們應當確保創建過程要產生一致狀態的對象。例如創建實體,應當滿足聚合的全部規則、創建值對象,應該被設置為默認的參數,如果無法創建參數,應該拋出異常,或者提供處理機制,確保不會影響代碼的執行。

2、工廠模式是一種抽象對象,而不是具體對象。意味著這個過程,不會產生具體對象,也就避免了與下層對象間不必要的耦合。

工廠模式不僅僅可以應用於對象生命周期的開始階段,也可以在對象的重建過程中發揮作用,例如在使用關系型數據庫和非關系數據庫組成的復雜體系中,通過對象映射技術,可以實現對現有數據的裝載。

領域倉儲對象

  在軟件系統研發過程中,我們通常需要使用SQL語句,直接調用基礎設施層中的某個方法,實現了一系列數據轉換。有時候,我們會引入AutoMap組件,實現從實體層到模型層對象的封裝,這種模式廣泛存在於我們的開發過程中,但是如果直接訪問基礎設施層,則可能增加對於數據庫不必要的操作,並導致模型的價值可有可無。而且隨著開發過程的推進,有可能會傾向於直接使用多次遍歷的方式,提取具體對象,而忽略了Aggregate,並使得實體層成為單純的數據容器。

  因此,通過引入倉儲模式,可以為我們的實現過程提供便利。通過倉儲模式,封裝一系列數據庫操作的方法,讓我們的註意力更關註於模型中。客戶端通過查詢方法,向倉儲中請求對象,然後再返回用戶所需的對象。

  這段代碼大概是這樣的:

  

public interface IRepository<T> where T : EntityBase
{
    T GetById(int id);
    IEnumerable<T> List();
    IEnumerable<T> List(Expression<Func<T, bool>> predicate);
    void Add(T entity);
    void Delete(T entity);
    void Edit(T entity);
} 

  倉儲的引入有很多優點:

  1、為訪問者提供簡單的模型,可用來獲取持久化對象並管理他們的生命周期。

   2、實現數據源解耦。

   3、實現了對象訪問策略的分離。

   4、便捷的訪問內存對象,減少對數據庫的吞吐壓力。

  在倉儲的設計過程中,應當註意一下事項:

   1、對類型進行抽象。倉儲的目的是為了傳遞具有特定類型的實例,但並非每個對象都有一個倉儲來與之對應。

   2、充分解耦。倉儲聚合不同的查詢方法,例如將關系數據庫和緩存數據庫的查詢方法進行封裝,使得代碼的過程變得易於操縱。

   3、事務可控。提供事務操作的方式,便於用戶自行實現事務的管理。

結語

在領域驅動設計中,通過在領域層中靈活的應用倉儲模式和工廠模式,實現對象的創建過程和傳遞過程的不同階段,可以讓代碼的執行過程更加的簡潔、關系更加的清晰,這也將客觀上有利於我們編寫出更加優秀的代碼。

領域驅動設計,讓程序員心中有碼(七)