大話設計模式之設計模式遵循的七大原則

?最近幾年來,人們踴躍的提倡和使用設計模式,其根本原因就是為了實現代碼的復用性,增加代碼的可維護性。設計模式的實現遵循了一些原則,從而達到代碼的復用性及增加可維護性的目的,設計模式對理解面向對象的三大特征有很好的啟發,不看設計模式,很難深層地體會到面向對象開發帶來的好處?。在剛開始學習中,很難做到將這些模式融匯貫通,所以這個需要我們在編碼前多思考,等想充分了,在開始實踐編碼。下面是設計模式應當遵循的七大原則

1.開閉原則(Open?Close?Principle)

定義:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。

??? 開放-封閉原則的意思就是說,你設計的時候,時刻要考慮,盡量讓這個類是足夠好,寫好了就不要去修改了,如果新需求來,我們增加一些類就完事了,原來的代碼能不動則不動。這個原則有兩個特性,一個是說“對于擴展是開放的”,另一個是說“對于更改是封閉的”。面對需求,對程序的改動是通過增加新代碼進行的,而不是更改現有的代碼。這就是“開放-封閉原則”的精神所在

??? 比如,剛開始需求只是寫加法程序,很快在client類中完成后,此時變化沒有發生,需求讓再添加一個減法功能,此時會發現增加功能需要修改原來這個類,這就違背了開放-封閉原則,于是你就應該考慮重構程序,增加一個抽象的運算類,通過一些面向對象的手段,如繼承、動態等來隔離具體加法、減法與client耦合,需求依然可以滿足,還能應對變化。此時需求要添加乘除法功能,就不需要再去更改client及加減法類,而是增加乘法和除法子類即可。
絕對的修改關閉是不可能的,無論模塊是多么的‘封閉‘,都會存在一些無法對之封閉的變化,既然不可能完全封閉,設計人員必須對于他設計的模塊應該對哪種變化封閉做出選擇。他必須先猜測出最有可能發生的變化種類,然后構造抽象來隔離那些變化。在我們最初編寫代碼時,假設變化不會發生,當變化發生時,我們就創建抽象來隔離以后發生同類的變化。

???? 我們希望的是在開發工作展開不久就知道可能發生的變化,查明可能發生的變化所等待的時候越長,要創建正確的抽象就越困難。開放-封閉原則是面向對象設計的核心所在,遵循這個原則可以帶來面向對象技術所聲稱的巨大好處,也就是可維護、可擴展、可復用、靈活性好。開發人員應該僅對程序中呈現出現頻繁變化的那些部分做出抽象,然而對于應用程序中的每個部分都刻意地進行抽象同樣不是一個好主意,拒絕不成熟的抽象和抽象本身一樣重要。開放-封閉原則,可以保證以前代碼的正確性,因為沒有修改以前代碼,所以可以保證開發人員專注于將設計放在新擴展的代碼上。

簡單的用一句經典的話來說:過去的事已成歷史,是不可修改的,因為時光不可倒流,但現在或明天計劃做什么,是可以自己決定(即擴展)的。

2.里氏代換原則(Liskov?Substitution?Principle)

定義1:如果對每一個類型為?T1的對象?o1,都有類型為?T2?的對象o2,使得以?T1定義的所有程序?P?在所有的對象?o1?都代換成?o2?時,程序?P?的行為沒有發生變化,那么類型?T2?是類型?T1?的子類型。

定義2:子類型必須能夠替換掉它們的父類型。
??? 描述:一個軟件實體如果使用的是一個父類的話,那么一定適用于其子類,而且它察覺不出父類對象和子類對象的區別,也就是說,在軟件里面,把父類都替換成它的子類,程序的行為沒有變化
例子:在生物學分類上,企鵝是一種鳥,但在編程世界里,企鵝卻不能繼承鳥。在面向對象設計時,子類擁有父類所有非private的行為和屬性,鳥會飛,但企鵝不會飛,所以企鵝不能繼承鳥類。

??? 只有當子類可以替換掉父類,軟件單位的功能不受影響時,父類才能真正被復用,而子類也能夠在父類的基礎上增加新的行為,正是有里氏代換原則,使得繼承復用成為了可能。正是由于子類型的可替換性才使得使用父類類型的模塊在無需修改的情況下就可以擴展,不然還談什么擴展開放,修改關閉呢

里氏替換原則通俗的來講就是:子類可以擴展父類的功能,但不能改變父類原有的功能。它包含以下4層含義:

1.子類可以實現父類的抽象方法,但不能覆蓋父類的非抽象方法。

2.子類中可以增加自己特有的方法。

3.當子類的方法重載父類的方法時,方法的前置條件(即方法的形參)要比父類方法的輸入參數更寬松。

4.當子類的方法實現父類的抽象方法時,方法的后置條件(即方法的返回值)要比父類更嚴格。

??? 看上去很不可思議,因為我們會發現在自己編程中常常會違反里氏替換原則,程序照樣跑的好好的。所以大家都會產生這樣的疑問,假如我非要不遵循里氏替換原則會有什么后果?

后果就是:你寫的代碼出問題的幾率將會大大增加。

3.依賴倒轉原則(Dependence?Inversion?Principle)

定義:高層模塊不應該依賴低層模塊,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。即針對接口編程,不要針對實現編程

??? 依賴倒轉其實就是誰也不要依靠誰,除了約定的接口,大家都可以靈活自如。依賴倒轉可以說是面向對象設計的標志,用哪種語言來編寫程序不重要,如果編寫時考慮的都是如何針對抽象編程而不是針對細節編程,即程序中所有的依賴關系都是終止于抽象類或者接口,那就是面向對象的設計,反之那就是過程化的設計了。如果設計的各個部件或類相互依賴,這樣就是耦合度高,難以維護和擴展,這也就體現不出面向對象的好處了。

??? 依賴倒轉原則,好比一個團隊,有需求組,開發組,測試組,開發組和測試組都是面對同樣的需求后,做自己相應的工作,而不應該是測試組按照開發組理解的需求去做測試用例,也就是說開發組和測試組都是直接面向需求組工作,大家的目的是一樣的,保證產品按時上線,需求是不依賴于開發和測試的。

??? 依賴倒置原則基于這樣一個事實:相對于細節的多變性,抽象的東西要穩定的多。以抽象為基礎搭建起來的架構比以細節為基礎搭建起來的架構要穩定的多。在java中,抽象指的是接口或者抽象類,細節就是具體的實現類,使用接口或者抽象類的目的是制定好規范和契約,而不去涉及任何具體的操作,把展現細節的任務交給他們的實現類去完成。

??? 依賴倒置原則的中心思想是面向接口編程,傳遞依賴關系有三種方式,以上的說的是是接口傳遞,另外還有兩種傳遞方式:構造方法傳遞和setter方法傳遞,相信用過Spring框架的,對依賴的傳遞方式一定不會陌生。

在實際編程中,我們一般需要做到如下3點:

低層模塊盡量都要有抽象類或接口,或者兩者都有。

變量的聲明類型盡量是抽象類或接口。

使用繼承時遵循里氏替換原則。

??? 總之,依賴倒置原則就是要我們面向接口編程,理解了面向接口編程,也就理解了依賴倒置。

4.接口隔離原則(Interface?Segregation?Principle)

???接口隔離原則的含義是:建立單一接口,不要建立龐大臃腫的接口,盡量細化接口,接口中的方法盡量少。也就是說,我們要為各個類建立專用的接口,而不要試圖去建立一個很龐大的接口供所有依賴它的類去調用。在程序設計中,依賴幾個專用的接口要比依賴一個綜合的接口更靈活。接口是設計時對外部設定的“契約”,通過分散定義多個接口,可以預防外來變更的擴散,提高系統的靈活性和可維護性。

?? 說到這里,很多人會覺的接口隔離原則跟單一職責原則很相似,其實不然。其一,單一職責原則原注重的是職責;而接口隔離原則注重對接口依賴的隔離。其二,單一職責原則主要是約束類,其次才是接口和方法,它針對的是程序中的實現和細節;而接口隔離原則主要約束接口接口,主要針對抽象,針對程序整體框架的構建。

采用接口隔離原則對接口進行約束時,要注意以下幾點:

1.?接口盡量小,但是要有限度。對接口進行細化可以提高程序設計靈活性是不掙的事實,但是如果過小,則會造成接口數量過多,使設計復雜化。所以一定要適度。

2.?為依賴接口的類定制服務,只暴露給調用的類它需要的方法,它不需要的方法則隱藏起來。只有專注地為一個模塊提供定制服務,才能建立最小的依賴關系。

3.?提高內聚,減少對外交互。使接口用最少的方法去完成最多的事情。

?? 運用接口隔離原則,一定要適度,接口設計的過大或過小都不好。設計接口的時候,只有多花些時間去思考和籌劃,才能準確地實踐這一原則。

4.組合/聚合復用原則

就是說要盡量的使用合成和聚合,而不是繼承關系達到復用的目的
該原則就是在一個新的對象里面使用一些已有的對象,使之成為新對象的一部分:新的對象通過向這些對象的委派達到復用已有功能的目的。
??????其實這里最終要的地方就是區分“has-a”和“is-a”的區別。相對于合成和聚合,
繼承的缺點在于:父類的方法全部暴露給子類。父類如果發生變化,子類也得發生變化。聚合的復用的時候就對另外的類依賴的比較的少。。
合成/聚合復用
①?優點:
新對象存取成分對象的唯一方法是通過成分對象的接口;
?這種復用是黑箱復用,因為成分對象的內部細節是新對象所看不見的;

?這種復用支持包裝;
這種復用所需的依賴較少;
每一個新的類可以將焦點集中在一個任務上;
?這種復用可以在運行時動態進行,新對象可以使用合成/聚合關系將新的責任委派到合適的對象。
②?缺點:
通過這種方式復用建造的系統會有較多的對象需要管理。

繼承復用
①?優點:
??新的實現較為容易,因為基類的大部分功能可以通過繼承關系自動進入派生類;
??修改或擴展繼承而來的實現較為容易。
②?缺點:
??繼承復用破壞包裝,因為繼承將基類的實現細節暴露給派生類,這種復用也稱為白箱復用;
??如果基類的實現發生改變,那么派生類的實現也不得不發生改變;
??從基類繼承而來的實現是靜態的,不可能在運行時發生改變,不夠靈活。
6.迪米特法則(Law?Of?Demeter)

??? 迪米特法則其根本思想,是強調了類之間的松耦合,類之間的耦合越弱,越有利于復用,一個處在弱耦合的類被修改,不會對有關系的類造成影響,也就是說,信息的隱藏促進了軟件的復用。

??? 自從我們接觸編程開始,就知道了軟件編程的總的原則:低耦合,高內聚。無論是面向過程編程還是面向對象編程,只有使各個模塊之間的耦合盡量的低,才能提高代碼的復用率。低耦合的優點不言而喻,但是怎么樣編程才能做到低耦合呢?那正是迪米特法則要去完成的。

??? 迪米特法則又叫最少知道原則,最早是在1987年由美國Northeastern?University的Ian?Holland提出。通俗的來講,就是一個類對自己依賴的類知道的越少越好。也就是說,對于被依賴的類來說,無論邏輯多么復雜,都盡量地的將邏輯封裝在類的內部,對外除了提供的public方法,不對外泄漏任何信息。迪米特法則還有一個更簡單的定義:只與直接的朋友通信。首先來解釋一下什么是直接的朋友:每個對象都會與其他對象有耦合關系,只要兩個對象之間有耦合關系,我們就說這兩個對象之間是朋友關系。耦合的方式很多,依賴、關聯、組合、聚合等。其中,我們稱出現成員變量、方法參數、方法返回值中的類為直接的朋友,而出現在局部變量中的類則不是直接的朋友。也就是說,陌生的類最好不要作為局部變量的形式出現在類的內部。

一句話總結就是:一個對象應該對其他對象保持最少的了解。

7.單一職責原則(Single?Responsibility?Principle)

定義:不要存在多于一個導致類變更的原因。通俗的說,即一個類只負責一項職責,應該僅有一個引起它變化的原因

??? 說到單一職責原則,很多人都會不屑一顧。因為它太簡單了。稍有經驗的程序員即使從來沒有讀過設計模式、從來沒有聽說過單一職責原則,在設計軟件時也會自覺的遵守這一重要原則,因為這是常識。在軟件編程中,誰也不希望因為修改了一個功能導致其他的功能發生故障。而避免出現這一問題的方法便是遵循單一職責原則。雖然單一職責原則如此簡單,并且被認為是常識,但是即便是經驗豐富的程序員寫出的程序,也會有違背這一原則的代碼存在。為什么會出現這種現象呢?因為有職責擴散。所謂職責擴散,就是因為某種原因,職責P被分化為粒度更細的職責P1和P2。

遵循單一職責原的優點有:

1.可以降低類的復雜度,一個類只負責一項職責,其邏輯肯定要比負責多項職責簡單的多;

2.提高類的可讀性,提高系統的可維護性;

3.變更引起的風險降低,變更是必然的,如果單一職責原則遵守的好,當修改一個功能時,可以顯著降低對其他功能的影響。

需要說明的一點是單一職責原則不只是面向對象編程思想所特有的,只要是模塊化的程序設計,都需要遵循這一重要原則。

?

轉載自:http://blog.csdn.net/csh624366188/article/details/7459918

轉載于:https://www.cnblogs.com/jiangdd/archive/2012/04/17/2454161.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/379792.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/379792.shtml
英文地址,請注明出處:http://en.pswp.cn/news/379792.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

IIC通信---EEPROM24C02---STMF4

IIC通信協議 IIC是同步半雙工通信,一個數據線SDA和一個時鐘SCL線,可以接受和發送數據。在CPU與被控IC之間、IC與IC之間進行雙向傳送。 空閑狀態 IIC總線的SDA和SCL兩條信號線同時處于高電平時,規定為總線的空閑狀態。 起始信號 當SCL為高…

實訓09.08:簡單的算法練習

/*final 關鍵字 修飾的變量值 后期不可更改 相當于定義常量常量 :不可更改*/final int a 10;//a 20; 報錯的值不可更改!/*輸入函數* */System.out.println("請輸入數字:");Scanner scanner new Scanner(System.in);int b…

讓自己閃亮

轉載于:https://www.cnblogs.com/Gigabyte/archive/2009/01/03/you_can_shine.html

Java中的wait()和sleep()方法之間的區別

Java中的wait()和sleep()方法 (wait() and sleep() methods in Java) First, we will see how wait() method differs from sleep() method in Java? 首先,我們將看到wait()方法與Java中的sleep()方法有何不同? wait()方法 (wait() Method) This metho…

離線使用iPhone SDK文檔的方法

在使用Xcode進行iPhone編程時,有時需要參考iPhone SDK的文檔,不過每次ControlClick后,Xcode都會試圖連接Internet,進行在線讀取。有什么方法能夠把資料下載到硬盤上進行離線閱讀嗎? 答案是肯定的。首先去Xcode的Prefer…

遠程連接sql server 2000服務器的解決方案

遠程連接sql server 2000服務器的解決方案2007-04-07 11:29遠程連接sql server 2000服務器的解決方案   一 看ping 服務器IP能否ping通。   這個實際上是看和遠程sql server 2000服務器的物理連接是否存在。如果不行,請檢查網絡,查看配置&#xff0c…

實訓09.10:HTML簡單表格設計

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>燕雨簡歷</title></head><body><table border"" cellspacing"" cellpadding"" width"400px" height"6…

LCD顯示實驗----STM32f4--HAL

步驟 LCD初始化 LCD_Init(); //LCD初始化此函數在lcd.c文件里面 2. 設置LCD背景顏色 LCD_Clear(WHITE);此函數在lcd.c文件里面 3. 設置字體顏色 POINT_COLORRED; 寫入要顯示的字體 LCD_ShowString(10,80,240,24,24,"LTDC TEST");LCD_ShowSt…

JavaScript | 使用提示從用戶輸入值

Example 1) Input name and print 示例1)輸入名稱和打印 Code (JS & HTML): 代碼(JS和HTML)&#xff1a; <!DOCTYPE html><HTML><HEAD><SCRIPT>var name prompt("Enter Your name:");var msg "Welcome "name;//alert(msg)…

一個游戲程序員的學習資料 (zz)

一個游戲程序員的學習資料//z 2012-4-19 14:39:51 PM IS2120CSDN想起寫這篇文章是在看侯杰先生的《深入淺出MFC》時, 突然覺得自己在大學這幾年關于游戲編程方面還算是有些心得&#xff0c;因此寫出這篇小文,介紹我眼中的游戲程序 員的書單與源代碼參考。一則是作為自己今后兩年…

項目管理中工作分解結構模型(WBSM)的應用

摘要 本文根據工作分解結構(WBS)的工作特點&#xff0c;運用系統工程的思想理論方法&#xff0c;構建了工作分解結構模型&#xff0c;并提出了模型算法;該模型方法的建立使得WBS工作更加簡單可靠、思路清晰、基于更加可靠的科學基礎之上。 1、工作分解結構模型(WBSM)方法工作程…

實訓09.11:java重點內容介紹

package test;/** * OP:面向對象的簡稱* 類&#xff1a;同一特征的屬性* * 類的定義&#xff1a;具有相同特征和行為的事物的抽象。&#xff08;不具體化&#xff09;* 對象&#xff08;實例對象&#xff09;&#xff1a;具體真實存在的實例。* 類是對象的實例&#xff1a;* *…

SPI通信原理---STM32F4--HAL

SPI接口原理 SPI是一種高速全雙工同步通信&#xff0c;在芯片管腳上占用四根線&#xff0c;主要應用在EEPROM、FLASH、實時時鐘、AD轉換器&#xff0c;還有數字信號處理器和數字信號解碼器之間。 SPI接口使用4根線通信。 MISO&#xff1a;主設備數據輸入&#xff0c;從設備數…

Linux 引導管理器 grub2 使用簡介

轉自&#xff1a;杜昌彬的空間 首先向其致敬&#xff01;有改動。 grub是Linux系統即其他類unix系統的主流bootloder&#xff0c;由于grub原來版本的設計存在很大缺陷&#xff0c;與以前的grub很不相同&#xff0c;其使用和配置也發生很大變化。現在很多Linux發行版本都使用了…

pata1015_ATA / PATA的完整形式是什么?

pata1015ATA / PATA&#xff1a;高級技術附件/并行高級技術附件 (ATA/PATA: Advanced Technology Attachment/Parallel Advanced Technology Attachment) ATA is an abbreviation of Advanced Technology Attachment. ATA has existed for a long time with the name PATA. Whe…

產品

總結一下&#xff1a;  1、核心功能要做透&#xff0c;做的人家追不上&#xff0c;自己的優勢要盡量的發揮&#xff1b;  2、產品口碑要建立&#xff0c;要關注高端用戶&#xff0c;要調整自己心態&#xff1b;  3、敏捷、快&#xff0c;產品迭代要快&#xff0c;快速實現…

FreeRTOS在STM32F429上移植

準備工作 FreeRTOS系統源碼基礎工程&#xff0c;這里我們用跑馬燈實驗 1.在工程里面添加FreeRTOS源碼 在工程里面新建一個名為FreeROTS的文件夾 將FreeRTOS源碼添加到這個文件夾里面 protable里面只需留下Keil、MemMang、RVDS文件夾 2、向工程分組中添加文件 FreeRTOS_C…

C++中的指針與引用(轉)

原文地址&#xff1a;http://www.cnblogs.com/skynet/archive/2010/09/22/1832911.html寫在前面 指針和引用形式上很好區別&#xff0c;但是他們似乎有相同的功能,都能夠直接引用對象&#xff0c;對其進行直接的操作。但是什么時候使用指針&#xff1f;什么時候使用引用呢&…

實訓09.11:數據庫一些簡單操作

new Database 新建數據庫 new Table 新建表 utf-8 編碼格式 primary key 主鍵&#xff1a;特點&#xff1a;在表中是唯一的不可重復的&#xff0c;一般都是學號&#xff0c;編號 auto increment 自增&#xff0c;一般都把主鍵設置為自增 allow nul…

c語言中將整數轉換成字符串_在C語言中將ASCII字符串(char [])轉換為八進制字符串(char [])...

c語言中將整數轉換成字符串Given an ASCII string (char[]) and we have to convert it into octal string (char[]) in C. 給定一個ASCII字符串(char [])&#xff0c;我們必須在C中將其轉換為八進制字符串(char [])。 Logic: 邏輯&#xff1a; To convert an ASCII string t…