聲明
本文為閱讀此書筆記摘要。內容來自網絡和本人手工輸入。發布在博客上不作為任何商業應用。存在有大段的原文引用,若存在版權問題,請聯系我,我將刪除。
Professional ASP.NET Design Patterns
為什么學習設計模式?
運用到ASP.NET應用程序中的設計模式、原則和最佳實踐。設計模式和原則支持松散耦合、高內聚的代碼,而這將提升代碼的可讀性、靈活性和可維護性。
對於那些已經有很好解決方法的任務,沒有理由再去進行重復勞動。
著名建築學家克里斯托弗·亞歷山大 Christopher Alexander 曾經說過:
每種模式描述了一個在我們周圍不斷重復發生的問題,以及該問題解決方案的核心,這樣你就可以一次又一次地使用該方案而不必做重復勞動。
約翰·列儂“沒有問題,只有出路”
.NET開發人員學習的必要性
微軟的RAD(Rapid application development)開發工具Visual Studio.NET快速開發表單式Web應用程序。通過簡單的拖曳和所見即所得的應用程序設計界面,使得人們能夠快速上手,一致的編程模型也有利於桌面應用程序開發者向Web應用程序開發轉移。此外,由於編碼模式與設計模式可以簡單地進行切換,平面設計師在設計階段就能夠看到與運行時接近的界面,而不必頻繁地運行調試模式或刷新網頁,這使平面設計師能全程參與應用程序開發,從而提高了開發效率。然而,這種固化的表單式應用程序設計模式也存在先天不足。隨着業務需求的變化和規模的不斷增長,如果仍然把所有的業務邏輯放在后置代碼中,將使代碼日益臃腫,而且存在大量的重復代碼。同時,這種Web表單式設計也不利於在應用程序中采用AJAX技術,很難在Web表單和Web服務程序之間共享代碼。掌握書中提到的設計理念和實現工具,對於更好地理解ASP.NET MVC框架中的概念頗有益處。
模式與設計原則
設計模式是高層次的、抽象的解決方案模板。可以將這些模式視為解決方案的藍本而不是解決方案本身。從中無法找到一種可以簡單地運用到應用程序中的框架;相反,通常是通過重構自己的代碼並將問題泛化來實現設計模式。
“四人組”(GoF)。他們收錄了23種設計模式並將它們歸納為3組。
● 創建型模式(Creational):處理對象構造和引用。
● 結構型模式(Structual):處理對象之間的關系以及它們之間如何進行交互以形成更大的復雜對象。
● 行為型模式(Behavioural):處理對象之間的通信,特別是在責任和算法方面。
模式是描述復雜問題的解決方案的有效方式。如果具備設計模式的牢固知識,就可以與團隊中的其他成員快速、順暢地溝通,而不必糾結於底層的實現細節。模式是語言不可知的。通過學習模式而獲得的知識將能夠運用於具體編程時采用的任何優秀的面向對象語言。
設計模式的宗旨就是重用解決方案。當然,並非所有問題都是一模一樣的,但如果能夠將一個問題分解,並找出它與以前解決過的問題之間的相似之處,就可以運用這些解決方案。即使您認為自己遇到的問題是獨特的,也應該可以通過將其分解成若干基本要素,將其泛化至一定程度,從而找出一種合適的解決方案。
設計模式的名稱非常有用,這是因為它反映出該模式的行為和目的,並為人們在集思廣益討論解決方案時提供常用的詞匯表。
陷阱:試圖把設計模式運用到所做的每件事情,但最終取得的效果卻與設計模式初衷(也就是讓事情變得簡單)相反。運用模式的較好方法是,通過識別正在試圖解決的基本問題,來尋找適合它的解決方案。
設計原則
設計原則構成了設計模式賴以構建的基礎。通過遵循經過驗證的設計原則,自己的代碼基會變得更加靈活、更能夠適應變化,而且可維護性更佳。
1. 簡約原則(KISS)
軟件編程領域普遍存在的一個問題是需要把解決方案過度復雜化。KISS原則的目標就是讓代碼保持簡潔但不要過於簡陋,從而避免引入任何不必要的復雜度。
2. 不要重復自已(DRY)
DRY原則的目的是通過將公用的部分抽離出來放在一個單獨的地方從而避免重復系統中的任何部分。這個原則不僅涉及代碼而且包括系統中重復的任何邏輯。最終,系統中的任何一部分知識都應該只有一種表示形式。
3. 講述而不要詢問(Tell, Don't Ask)
“講述而不要詢問”原則體現了封裝以及將責任指派到正確的類這兩個思想。這個原則要求,應該告訴對象您希望它們執行什么動作,而不是詢問有關該對象狀態的問題然后由您自己決定希望執行什么動作。這個原則有助於匹配責任並避免類之間的緊密耦合。
4. 您不需要它(YAGNI)
YAGNI原則指的是只需要將應用程序必需的功能包含進來,而不要試圖添加任何其他您認為可能需要的功能。測試驅動開發(TDD)就是一種堅持YAGNI原則的設計方法學。TDD的宗旨就是編寫測試來驗證系統的功能,然后只需要編寫可讓測試通過的代碼即可。
5. 分離關注點(SoC)
SoC這一過程將軟件分解為多項不同的功能,每項功能封裝了可供其他類使用的唯一行為和數據。通常,一個關注點代表類的一項功能或行為。將程序划分成若干獨立職責的做法顯著提高了代碼的重用程度、維護性和可測試性。
S.O.L.I.D.設計原則
S.O.L.I.D.設計原則是一組針對面向對象設計的最佳實踐。術語S.O.L.I.D.來自於Robert C. Martin(朋友們親切地稱呼他Bob大叔)的著作Agile Principles, Patterns, and Practices in C#中收集的5個設計原則的名稱的首字母。
1. 單一責任原則(SRP)
SRP原則與SoC原則保持高度一致。它要求每個對象只應該為一個元素而改變而且只有一個職責關注點。遵循這個原則,就可以避免單體類(就像是軟件領域的瑞士軍刀)設計問題。使每個類均保持簡潔,就可以提升系統的可讀性和可維護性。
2. 開放封閉原則(OCP)
OCP原則要求類對於擴展應該是開放的,而對於修改應該是封閉的,這樣應該就能夠在不改變類的內部行為的情況下添加新功能並擴展類。這個原則努力避免破壞已有的類以及其他依賴它的類,因為這會在應用程序中造成bug和錯誤的漣漪效應。
3. 里氏替換原則(LSP)
LSP原則指出應該能夠使用任何繼承類來替代父類並且讓其行為方式保持不變。這個原則與OCP原則保持一致:它確保繼承類不會影響父類的行為,換句話來說,繼承類必須可替代它們的基類。
4. 接口分離原則(ISP)
ISP原則關注的是將契約的方法划分成若干職責分組,並且為這些分組指派不同的接口,這樣客戶端就不需要實現一個龐大的接口和一堆它們並不使用的方法。這個原則背后的目的是:使用相同接口的類只需要實現特定的一組方法,而不是實現一個龐大的單體方法接口。
5. 依賴倒置原則(DIP)
DIP原則的宗旨是將自己編寫的類與具體的實現隔離開來,讓這些類依賴於抽象類或接口。它提倡面向接口(而不是實現)編程,這確保代碼不會與某種實現緊密耦合,從而提高了系統的靈活性。
6. 依賴注入(DI)和控制反轉(IoC)原則
與DIP緊密相關的是DI原則和IoC原則。DI通過構造器、方法或屬性來提供底層類或從屬類。配合使用DI原則,這些從屬類可以被反轉為接口或抽象類,這樣就可以形成一個具有較高的可測試性和易於修改的松散耦合系統。
在IoC原則中,系統的控制流與過程式編程方法相比是反轉的。這個原則的一個示例是IoC容器,它的作用是將服務注入到客戶端代碼,而不必讓客戶端代碼指定具體的實現。在該實例中,控制反轉指的是客戶端獲取服務的行為。
Fowler的企業設計模式
Martin Fowler的著作Patterns of Enterprise Application Architecture是有關如何構建企業級應用程序的最佳實踐和模式的參考書。
領域邏輯模式
組織業務邏輯的3種常見方法:Transaction Script(事務腳本)、Active Record(活動記錄)及Domain Model(領域模型)。
1. Transaction Script
Transaction Script模式按照線性的、過程式方法來組織業務邏輯。它將細粒度的業務用例映射為細粒度的方法。
2. Active Record
Active Record模式按照一種能夠緊密匹配底層數據結構的方式來組織業務邏輯,即表中表示數據行的對象。
3. Domain Model
Domain Model模式是對現實領域對象的抽象。同時對數據和行為建模。對象之間可以存在與真實領域相匹配的復雜關系。
對象關系映射
支持持久化的基礎設施代碼所需的企業模式。
1. Unit of Work
Unit of Work(工作單元)模式用來維護一個由已經經過業務事務修改(添加、刪除或更新)的業務對象構成的列表。然后,Unit of Work模式負責將這些發生變化的對象的持久化工作協調成為一個原子動作。如果出現問題,整個事務就會回滾。
2. Repository
Repository(資源庫)模式大體上用於對象的邏輯集合,它們更為人知的名字叫做聚合(aggregate)。它充當業務實體的內存集合或倉庫,完全將底層數據基礎設施抽象出來。
3. Data Mapper
Data Mapper(數據映射器)模式用來從原始數據中提取信息以生成對象,以及將業務對象中的信息轉換到數據庫。業務對象和數據庫彼此互不了解。
4. Identity Map
Identity Map(標識映射)模式監視每一個從數據庫中加載的對象,確保所有對象只加載一次。當后面請求該對象時,在從數據庫檢索之前先檢查標志映射。
5. Lazy Loading
Lazy Loading(惰性加載或延遲加載)模式將獲取資源的過程推遲到真正需要用到該資源的時候。
6. Query Object
Query Object(查詢對象)模式是GoF的Interpreter(解釋器)設計模式的一種實現。查詢對象充當一種從底層數據庫中抽象出來的面向對象查詢,它引用的是屬性和類,而不是真正的表和列。通常,還需要使用一個翻譯器對象來生成用於查詢數據庫的原生SQL語句。
Web表示模式
將領域和表示邏輯分離同時讓表示層能夠有效測試的模式。這些模式的任務都是將用於表示的邏輯關注點與業務邏輯關注點分離。ASP.NET表示需要所涵蓋的模式有:
● Model-View-Presenter(模型-視圖-表示器)。
● Model-View-Controller(模型-視圖-控制器)。
● Front Controller(前端控制器)。
● Page Controller(頁面控制器)。
Fowler著作中的其他企業模式
1. Null Object模式
Null Object(空對象)模式也稱為Special Case(特殊情況)模式,它充當返回值而不是向調用代碼返回null。空對象將與預期結果共享相同的接口或者從相同的基類繼承而來,這樣減少了在代碼基中到處檢查null情況的需要。
2. Separated Interface模式
Separated Interface(獨立接口)模式要求將接口放在一個獨立於具體實現的程序集或命名空間中。這確保客戶端完全不知道具體實現,而且能夠遵循面向抽象編程(而不是面向實現)以及依賴倒置原則。
3. Gateway模式
Gateway(網關)模式允許客戶端通過一個簡化的接口來訪問復雜的資源。網關對象基本上將資源API包裝成一個能夠在應用程序中到處使用的單個方法調用。此外,它還隱藏了所有的API復雜性。
TDD(Test-driven Development,測試驅動設計)並不像它的名稱所言,它更多的是一種設計方法學而不是測試策略。這種設計方法學背后的主要思想是使用測試來塑造系統的設計。在創建軟件解決方案時,首先編寫一個導致測試失敗的測試程序來斷言某種業務邏輯。然后編寫代碼讓測試通過。最終,通過重構來清理所有代碼。這三步已經被人們稱為紅-綠-重構(red-green-refactor)。紅和綠指的是測試框架分別用來顯示測試通過和測試失敗的顏色。
通過經歷TDD流程,最終將得到一個帶有一套可以確認所有行為的測試的松耦合系統。TDD的一個副產品是這些測試提供了一種描述系統能夠做什么以及不能做什么的文檔。因為測試屬於系統的一部分,所以它絕不會過時,這與編寫的文檔和代碼注釋不同。
● Test Driven Development: By Example,Kent Beck著
● The Art of Unit Testing: With Examples in .NET,Roy Osherove著
● Professional Enterprise .NET,Jon Arking與Scott Millett合著(Wrox出版)
DDD(Domain-driven Design,領域驅動設計)是一組有助於構建反映對業務的理解並滿足業務需求的應用程序的模式和原則。除此之外,它是一種思考開發方法學的全新方式。DDD的建模方式如下:首先通過全面理解真實領域來對真實領域建模,然后將所有的術語、規則和邏輯放到代碼的某種抽象表示中(通常是以領域模型的形式)。雖然DDD並不是一種框架,但是它確實有一組構建塊或概念可以整合到解決方案中。
● Domain-Driven Design: Tackling Complexity in the Heart of Software,Eric Evans著
● Applying Domain-Driven Design and Patterns: With Examples in C# and .NET,Jimmy Nilsson著
● .NET Domain-Driven Design with C#: Problem - Design -
BDD(Behavior-driven Design,行為驅動設計)被視為TDD與DDD合並的結果。BDD關注系統的行為而不僅僅是測試它。使用BDD時所創建的規范可以使用在真實領域中隨處可見的語言,這能夠讓技術用戶和業務用戶同時受益。
采用BDD編寫規范時產生的文檔可以讓讀者了解系統在各種情況下表現什么樣的行為,而不是簡單地驗證各個方法正在執行它們應該完成的工作。通過將DDD的若干方面與核心TDD概念有機融合,BDD將同時滿足業務用戶和技術用戶的需求。可以使用標准的單元測試框架來執行BDD,但專門的BDD框架已經出現了,而且BDD即將成為下一個大事件。
怎樣學習
名稱和意圖 反映該模式或原則的目的、用法、好處以及使用該模式的動機。
UML圖
展示模式或原則的結構的圖形化表示。圖形化表示用來顯示通用的解決方案模版以及其實現。
代碼實現
如何選擇和運用設計模式
●在不了解模式的情況下不能運用它們。首先擴大自己的知識面並采用從抽象到具體的方法來學習模式和原則。
●是否有必要引入設計模式的復雜性。需要衡量實現某種模式所需的時間與該模式能夠帶來的收益。謹記KISS原則。
●講問題泛化,已更抽象的方式識別正在處理問題。了解每個模式和原則是如何編寫的。並了解自己需要解決的問題是否符合特定模式或原則試圖解決的問題。設計模式是高層次的激將法解決方案,試着把問題抽象,不要過於關注具體問題的細節。
●了解具有類似性質的模式以及同組中的其他模式。
●封裝變化的部分。了解應用程序中什么可能發生變化。
●在選擇好設計模式之后,確保在命名解決方案中的參與者使用該模式的語言及領域語言。FedExShippingCostStrategy 使用策略模式為不同的快遞公司計價