歡迎光臨
每天分享高質量文章

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

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

-設計原則和設計樣式,網際網路開發者們共同的追求

      前言

  多年來,筆者一直從事傳統軟體企業的軟體開發和專案管理工作。筆者發現在眾多的傳統軟體企業中,評判優秀開發者的標準往往是技能的熟練程度,基本上都是以梭程式碼的速度論英雄。有人評價說,這種開發可以稱之為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 where T : EntityBase
{
T GetById(
int id);
IEnumerable
List();
IEnumerable
List(Expressionbool>> predicate);
void Add(T entity);
void Delete(T entity);    void Edit(T entity);
}

 

  倉儲的引入有很多優點:

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

      2、實現資料源解耦。

      3、實現了物件訪問策略的分離。

      4、便捷的訪問記憶體物件,減少對資料庫的吞吐壓力。

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

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

      2、充分解耦。倉儲聚合不同的查詢方法,例如將關係資料庫和快取資料庫的查詢方法進行封裝,使得程式碼的過程變得易於操縱。

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

      結語

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

贊(0)

分享創造快樂