領域驅動設計與面向對象的一點想法


領域驅動設計與面向對象的一點想法

我的Github

本文只是我在閱讀了《領域驅動設計》這本書以后的一點淺薄的理解和認知,如果有不正確的地方還請大家指出=_=。

什么是計算機軟件

software

如上圖所示,我所理解的計算機軟件是通過使用程序的概念與現實世界中的事物進行映射,最終實現影響現實世界的計算機程序。

如何進行映射

面向過程設計

面向過程其實是一種與人的思維方式很一致的設計方法,將一個事情的處理步驟按照順序的去執行。在這過程中一般都會使用Top-Down的方法,自頂向下逐步求精的逐步分解一個任務。並且在這個過程中考慮分層,模塊化等具體的組織方式,從而分解軟件的復雜度。當軟件的復雜度不是很大或者要實現的功能的模型與面向過程的設計很契合的情景中,面向過程是一種簡單直觀的設計方法,也能得到很好的效果。

面向對象設計

面向對象的程序設計通過將現實世界中的事物概念映射到程序設計中的“對象”概念上,現實世界中事物的屬性和行為映射到“對象”的屬性和方法。程序通過各種對象之間的調用以及協作,從而實現計算機軟件的功能。跟很多工程方法一樣,面向設計的初衷就是一種處理軟件復雜度的設計方法。

面向對象程序設計可以看作一種在程序中包含各種獨立而又互相調用的對象的思想,這與傳統的思想剛好相反:傳統的程序設計主張將程序看作一系列函數的集合,或者直接就是一系列對電腦下達的指令。面向對象程序設計中的每一個對象都應該能夠接受數據、處理數據並將數據傳達給其它對象,因此它們都可以被看作一個對象。目前已經被證實的是,面向對象程序設計推廣了程序的靈活性和可維護性,並且在大型項目設計中廣為應用。此外,支持者聲稱面向對象程序設計要比以往的做法更加便於學習,因為它能夠讓人們更簡單地設計並維護程序,使得程序更加便於分析、設計、理解。

面向對象設計的原則

S.O.L.I.D

The Single Responsibility Principle SRP

如果要在這些原則里面選一條最重要的,那么毫無疑問我會選單一職責原則,這個原則的本質就是我們的設計和實現的對象和實體在各自的概念層次上面都應該是高內聚的。我認為單一職責原則並不是面向對象設計才有的原則,它的適用性非常廣泛。我理解的單一職責原則是這樣的,對於一個層次上的抽象對象,它只表達或者負責一個這個層次上的概念。比如一個方法只負責單一的行為,一個類只表示單一的概念,一個模塊只負責這個模塊所表示的單一概念的屬性和操作,一個子系統只負責屬於這個子系統概念邊界內的流程;在面向過程的設計中這個原則同樣適用,比如分層模型中一個層只負責這個層的功能並且與上下層的邊界要划分清楚。所以說單一職責原則在設計和實現的過程中都具有很廣泛的適用性。

The Open/Closed Principle OCP

開閉原則,軟件對象實體應該對擴展開放對修改關閉。在需求變動的時候,最好的不需要對原有的設計和代碼做改動,而是增加一些類就可以滿足需要。 要做到開閉原則,1.抽象,恰當的抽象才能將邏輯或者對象抽象成為可復用和易擴展的組件。2.封裝變化,預先將可預測的變動點進行封裝抽象,從而可以不修改已有邏輯。

The Liskov Substitution Principle LSP

里氏替換原則,一個子類可以替換他們的父類。即子類應該擁有父類的所有操作,實現IS-A的關系。

The Interface Segregation Principle ISP

接口要小而專,不要大而全。也就是說接口的設計也要高內聚,這樣就減少了客戶端依賴額外的需需要的接口,減少各個模塊之間的耦合。

The Dependency Inversion Principle DIP

依賴反轉原則,也就是面向接口編程。具體的說一個類依賴的屬性盡量不要直接依賴具體的實現,而是依賴接口或者是abstract類。這樣更容易解耦,從而實現OCP。

Composite/Aggregate Reuse Principle CARP

優先使用聚合或組合關系復用代碼。 類與類之間簡單的關系有Is-A,Has-A,Use-A,對應着繼承,關聯和依賴。而他們的耦合關系是繼承>關聯>依賴。而且使用繼承的時候盡量要保證子類與父類之間是Is-A關系。所以盡可能使用聚合關系,除非它們真的適用繼承關系。

Law of demeter LOD

一個軟件實體應當盡可能少的與其他實體發生相互作用。每一個軟件單位對其他的單位都只有最少的知識,而且局限於那些與本單位密切相關的軟件單位。這是強調了低耦合的重要性。

領域驅動設計

在文章開頭的那張圖中,我覺得軟件與現實重疊的地方就是我們所說的領域。而領域驅動開發也並不是多么神奇的東西,它其實只是面向對象設計的一種方法而已。它是一種與敏捷開發相適應的對系統進行逐步迭代的面向對象的分析和建模方法。

領域知識

所謂領域知識就是指軟件所需要處理的業務的流程,相關概念。這個知識需要從領域專家,或者領域相關的書籍中獲取,所謂領域專家也就是你的用戶,或者是相關的對這些業務很熟悉的人員。你有可能會認為這個就是需求獲取,是產品經理的事情,但是很多時候產品經理所提供的信息並不足以讓你設計出符合領域的模型,而且產品經理往往缺乏系統建模的知識,另外,信息在傳遞的過程中往往還有損耗,你從產品經理那里得到的信息或許已經少了很多細節。所以最好的方式還是能直接與領域專家進行交流,從而得到設計領域模型所需要的信息。

UBIQUITOUS LANGUAGE

在與領域專家進行交流的時候,經常會有那么一種情況,就是領域專家說的話開發人員聽不懂,開發人員說的話領域專家也不能很好的理解,這樣就導致了溝通的效率低下。所以在交流的時候,雙方需要對同一個概念有一個統一的描述和理解,並且這些UBIQUITOUS LANGUAGE不僅僅在與領域專家交流的時候使用,並且在領域建模和后續的實現都要持續的使用下去。要讓從業務專家到開發人員都能對這些詞匯概念有統一的認識。

模型和實現的關系

領域模型應該與軟件實現是相對應的,模型的修改必然會導致代碼的修改。並且有一些隱式的領域概念在軟件的實現中應該在領域模型中體現出來,這是一種抽象的層次,可以減少領域模型的復雜度。比如說,在某個業務場景中,有利息,手續費,等等要收的資金,這時候可以考慮它們能不能抽象成費用這個隱式的概念,並且在領域模型中嘗試着加入這個概念的對象,驗證是否可以將模型變得更為的合理。

在實際的實現過程中,往往會出現開發人員對模型理解有偏差,導致實現與模型不符合的情況。或者實際的開發人員不認同所設計的模型,在開發過程中可能會根據自己的理解去實現,最終導致了實現與領域模型不相符。所以領域驅動強調模型設計人員必須在開發流程中保證實現與模型是相符的,它提倡模型設計人員也應該是開發人員。現在有很多設計人員都會認為自己只負責設計,而不去保證實現符合設計,這在實際的項目開發過程中大概率會導致實現與模型不符合。還有一些設計人員認為,所謂的設計就是數據庫模型設計,其他的都不重要,還有就是設計人員只負責設計,怎么實現就不關心了;根據領域驅動設計的說法,這種想法也是錯誤的,因為我們的目標是實現一個符合領域模型的軟件,而所謂的設計並不狹隘的指數據庫模型設計,還有模塊和類的設計,這些對於實現我們的目標都是很重要的。雖然數據庫的模型很大程度上反映了領域模型,但是領域模型的信息含量遠比數據庫模型要多,一開始就直接動手設計數據庫而不是分析領域往往會導致很多隱藏的問題在開發的過程中才暴露出來,導致在開發過程中還在不斷的修改表結構。

分離領域

分離領域更多的是強調在實現的過程中在模塊划分和代碼組織上講核心的領域模型與其他模塊隔離開來,這也是封裝變化的一種體現。比如核心的業務模型代碼與view層和基礎服務代碼分離,這樣可以得到更為內聚的模塊划分,並且可以更靈活的對領域模型進行重構而降低對其他模塊的影響。

逐步迭代

在實際的執行過程中,一開始就能把領域知識完全理解是很困難的,也不符合人類的認知模型,所以領域驅動設計提倡的是逐步迭代的方法。領域驅動設計也是與敏捷開發相契合的。在開發的過程中不斷的去理解和消化領域知識,發現現有模型的缺陷或者發現新的對象能將現有模型變得更合理的時候再修改現有的模型。這本來就是敏捷開發逐步迭代的做法。

注重重構

我們所說的重構一般是指代碼級別的改進,比如《重構》和《代碼整潔之道》里面的方法,但是在領域驅動設計的概念中,重構更偏重於領域模型上的重構。在迭代的過程中,可能在對領域理解的程度加深以后會發現現有的領域模型可以如何改進得更符合領域知識。這時候就應該更新現有的領域模型,因為實現與領域模型是一致的,所以也要對代碼實現進行修改。但是在現實的工作中並不是每個人都有這個認知,所以當一個重構點被提出來,有可能因為還有其他功能要實現,或者領導認為重構沒有績效,導致重構一致得不到執行,然后架構就在一次次的迭代過程中不斷腐化,每次迭代效率越來越低。這就要各位開發人員提升自己的談判技巧了=_=

最后

書中我印象最為深刻的一句話,它的大意是“我們並不是能夠預測到需求的變化,我們只是把模型設計的盡量符合領域而已。”


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM