深入淺出精講面向對象設計七大原則,徹底領悟設計背后思想-創(chuàng)新互聯

深入淺出精講面向對象設計七大原則,徹底領悟設計背后思想
  • 歡迎閱讀
    • 一、面向對象設計原則提出背景
    • 二、面向對象設計七大原則總覽
    • 三、單一職責原則(SRP)
      • 3.1定義:
      • 3.2分析:
      • 3.3舉例:
    • 四、開閉原則(OCP)
      • 4.1定義:
      • 4.2分析:
      • 4.3舉例:
    • 五、里氏替換原則(LSP)
      • 5.1定義:
      • 5.2分析:
      • 5.3舉例:
    • 六、依賴倒轉原則(DIP)
      • 6.1定義:
      • 6.2分析:
      • 6.3舉例:
    • 七、接口隔離原則(ISP)
      • 7.1定義:
      • 7.2分析:
      • 7.3舉例:
    • 八、迪米特法則(LOD)
      • 8.1定義:
      • 8.2分析:
      • 8.3舉例:
    • 九、合成復用口原則(CRP)
      • 9.1定義:
      • 9.2分析:
      • 9.3舉例:
    • 十、面向對象設計原則總結

創(chuàng)新互聯建站是一家集成都網站設計、成都網站制作、網站頁面設計、網站優(yōu)化SEO優(yōu)化為一體的專業(yè)網站制作公司,已為成都等多地近百家企業(yè)提供網站建設服務。追求良好的瀏覽體驗,以探求精品塑造與理念升華,設計最適合用戶的網站頁面。 合作只是第一步,服務才是根本,我們始終堅持講誠信,負責任的原則,為您進行細心、貼心、認真的服務,與眾多客戶在蓬勃發(fā)展的市場環(huán)境中,互促共生。歡迎閱讀

對面向對象設計原則的學習能夠提高大家的系統(tǒng)設計能力和代碼編寫質量。本文內容豐富易懂,對每一個面向對象設計原則都會舉出具體的例子來進行講解。在文章最后會對所有的面向對象設計原則進行總結。另外,本篇文章有配套的講解視頻(如果不想看文字就去看視頻叭),請點擊這里觀看(嗶哩嗶哩-小勾狗有什么壞心眼呢-bili_88094125658)。歡迎大家閱讀和觀看~希望通過這篇文章的分享能夠使得大家在今后利用面向對象語言編寫代碼時給大家?guī)硪恍椭?/p>一、面向對象設計原則提出背景

對于我們后端來說,平時大部分時間都在使用面向對象語言來設計軟件系統(tǒng)。對于面向對象軟件系統(tǒng)的設計而言,在支持可維護性的同時,提高系統(tǒng)的可復用性是一個至關重要的問題,如何同時提高一個軟件系統(tǒng)的可維護性和可復用性是面向對象設計需要解決的核心問題之一。像我們平時接觸的23種設計模式就是以面向對象七大原則為基礎進行設計的。所以對面向對象設計的七大原則的學習有助于提高我們的設計水平,使我們設計的軟件系統(tǒng)有較高的可維護性和可復用性。今天呢,我會通過具體案例,深入淺出精講面向對象設計七大原則,讓大家徹底領悟設計背后的思想。

二、面向對象設計七大原則總覽

這張表展示了今天會分享到的七大原則。下面我會結合具體的例子來一一分享各個原則。

設計原則名稱設計原則簡介
單一職責原則(Single Responsibility Principle, SRP)類的職責要單一,不能將太多的職責放在一個類中
開閉原則(Open-Closed Principle, OCP)軟件實體對擴展是開放的,但對修改是關閉的,即在不修改一個軟件實體的基礎上去擴展其功能
里氏代換原則(Liskov Substitution Principle, LSP)在軟件系統(tǒng)中,一個可以接受基類對象的地方必然可以接受一個子類對象
依賴倒轉原則(Dependency Inversion Principle, DIP)要針對抽象層編程,而不要針對具體類編程
接口隔離原則(Interface Segregation Principle, ISP)使用多個專門的接口來取代一個統(tǒng)一的接口
合成復用原則(Composite Reuse Principle, CRP)在系統(tǒng)中應該盡量多使用組合和聚合關聯關系,盡量少使用甚至不使用繼承關系
迪米特法則(Law of Demeter, LoD)一個軟件實體對其他實體的引用越少越好,或者說如果兩個類不必彼此直接通信,那么這兩個類就不應當發(fā)生直接的相互作用,而是通過引入一個第三者發(fā)生間接交互
三、單一職責原則(SRP) 3.1定義:

首先來看第一個原則,單一職責原則。單一職責原則有兩種定義方式。
第一種定義是一個對象應該只包含單一的職責,并且該職責被完整地封裝在一個類中。(Every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class.)
第二種定義是就一個類而言,應該僅有一個引起它變化的原因。(There should never be more than one reason for a class to change.)

3.2分析:

下面我們做一個具體分析。類的職責主要包括兩個方面:數據職責和行為職責,數據職責通過其屬性來體現,而行為職責通過其方法來體現。顯而易見,一個類(或者大到模塊,小到方法)承擔的職責越多,它被復用的可能性越小,而且如果一個類承擔的職責過多,就相當于將這些職責耦合在一起,當其中一個職責變化時,可能會影響其他職責的運作。

3.3舉例:

下面通過舉例Java的C/S系統(tǒng)的“登錄功能”來說明單一職責原則。在圖中,登錄類中的init方法是初始化方法、display是顯示方法、validate是數據驗證方法、getConnection是鏈接數據庫的方法、findUser是通過數據庫校驗用戶名和密碼的方法、main方法是整個系統(tǒng)運行的方法?,F在我們來看看他是不是符合單一職責原則。單一職責原則是一個類應該只包含一個單一的職責,而現在我們看到,Login類中其實包含了三種職責。首先是init方法、display方法和validate方法組成的展示頁面的職責、然后是getConnection方法和findUser方法組成的查詢數據庫的職責、最后是main方法構成的運行整個系統(tǒng)的職責。我們說就一個類而言,應該僅有一個引起它變化的原因。如果說我們現在需要對顯示做變換,那么我們需要修改display方法從而導致Login類被修改、而如果我們說現在需要修改數據庫的鏈接方式,那么我們需要修改getConnection方法同樣會導致Login類被修改,再如果說我們要修改main方法比如在運行前需要添加一下處理,那么就需要修改Login類種main方法。所以說Login類現在能引起它變化的原因有很多種。這顯然不太好。

在這里插入圖片描述
現在我們使用單一職責原則對其進行重構。對于這四個類的介紹,可以點擊這里觀看視頻(在5分00秒處)。現在我們看到我們把Login類劃分成了四個不同的類,每個類有自己的單一職責,也就是說每一個類現在引起他們變換的原因都只有一個。也就是說現在四個類是四個正交的維度,他們之間的變換是無關的。像現在這樣的設計就符合了單一職責原則。這樣當因為變化需要修改時,就可以只修改對應的模塊而不用影響其它的模塊??梢钥吹浆F在的設計,在可維護性和可復用性上都比之前的設計好很多了。比如說我們想更改getConnection方法,那么我們只會去修改UserDAO類,而其它類不會受到影響。而且引起UserDAO發(fā)生改變的原因只有一個,而不是很多個。
在這里插入圖片描述

四、開閉原則(OCP) 4.1定義:

第二個原則,開閉原則。開閉原則定義是一個軟件實體應當對擴展開放,對修改關閉。(Software entities should be open for extension, but closed for modification.)也就是說在設計一個模塊的時候,應當使這個模塊可以在不被修改的前提下被擴展,即實現在不修改源代碼的情況下改變這個模塊的行為。

4.2分析:

開閉原則由Bertrand Meyer于1988年提出,也就是下面圖片中的這個人,旁邊這兩本經典的書就是他寫的。開閉原則是面向對象設計中最重要的原則之一。在開閉原則的定義中,軟件實體可以指一個軟件模塊、一個由多個類組成的局部結構或一個獨立的類。在開閉原則中,抽象化是它的關鍵。開閉原則還可以通過一個更加具體的“對可變性封裝原則”(Principle of Encapsulation of Variation, EVP)來描述,其中“對可變性封裝原則”要求找到系統(tǒng)的可變因素并將其封裝起來。
在這里插入圖片描述

4.3舉例:

現在通過舉例圖像界面系統(tǒng)中各種不同的按鈕來說明開閉原則的應用。某圖形界面系統(tǒng)提供了各種不同形狀的按鈕,客戶端代碼可針對這些按鈕進行編程,用戶可能會改變需求要求使用不同的按鈕,原始設計方案如圖所示。其中LoginForm是登錄頁面,包含一個button按鈕,display顯示方法會根據不同類型的button按鈕展示不同樣式的button。可以看到,每當需要變換按鈕時,需要修改LoginForm中的代碼,而這違反了開閉原則中所說的對修改關閉。另外,如果用戶需要新的Button時,需要重新定義一個button然后修改LoginForm的代碼,這對擴展很不方便?,F在我們需要思考如何更改設計,來達到在不修改代碼的情況下做到擴展。
在這里插入圖片描述
在這里插入圖片描述
現在我們使用開閉原則對其進行重構。重新構造后的結構如圖所示。對于這張圖的介紹,可以點擊這里觀看視頻(在9分37秒處)?,F在,當我們需要變換按鈕時只需要修改配置文件就可以改變按鈕的樣式了,另外,如果有新的按鈕,我們只需要增加一個新button類繼承AbstractButton,然后修改配置文件就可以很方便地進行擴展了,可以看到我們并沒有修改任何LoginForm中的代碼就實現了擴展,現在的設計比之前的設計好了很多。
在這里插入圖片描述
這里的配置文件可以讓LoginForm中AbstractButton類型的button對象是配置文件中指定的類(例如圖中是CircleButton)的實例。

五、里氏替換原則(LSP) 5.1定義:

第三個原則,里氏替換原則。里氏替換原則有兩種方式的定義,第一個定義是:如果對每一個類型為S的對象o1,都有類型為T的對象o2,使得以T定義的所有程序P在所有的對象o2都代換成o1時,程序P的行為沒有變化,那么類型S是類型T的子類型。(If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.)

第二定義是:所有引用基類(父類)的地方必須能透明地使用其子類的對象。(Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.)

其中定義一比較重要的一點是替換后行為沒有發(fā)生變化,也就是說如果替換后行為發(fā)生了變化或者代碼運行時出現行為/業(yè)務錯誤,那么這兩個類就不應該是父子關系。定義二中比較重要的是透明這一個詞,透明的含義是指,當基類被子類替換時,感覺不到基類被子類替換了,也就是行為不會發(fā)生變化。

5.2分析:

里氏代換原則由2008年圖靈獎得主、美國第一位計算機科學女博士、麻省理工學院教授Barbara Liskov和卡內基.梅隆大學Jeannette Wing教授于1994年提出。也就是下面這兩位。里氏代換原則可以通俗表述為:在軟件中如果能夠使用基類對象,那么一定能夠使用其子類對象。把基類都替換成它的子類,程序將不會產生任何錯誤和異常,反過來則不成立,如果一個軟件實體使用的是一個子類的話,那么它不一定能夠使用基類。里氏代換原則是實現開閉原則的重要方式之一,由于使用基類對象的地方都可以使用子類對象,因此在程序中盡量使用基類類型來對對象進行定義,而在運行時再確定其子類類型,用子類對象來替換父類對象。
在這里插入圖片描述
在這里插入圖片描述

5.3舉例:

現在通過舉例對數據進行加密來說明里氏替換原則的應用。(這里舉例比較復雜,建議觀看視頻(在13分57秒處)。)如圖所示,某系統(tǒng)現在需要對重要數據,如用戶密碼,進行加密處理,在數據操作類DataOperator中需要調用加密類中定義的加密算法encrypt,系統(tǒng)提供了兩個不同的加密類,CipherA和CipherB,它們實現不同的加密方法,在DataOperator中可以選擇其中一個實現加密操作?,F在考慮一個問題,如果需要更換一個加密算法類或者增加并使用一個新的加密算法類,如將CipherA改為CipherB(Client中的main方法需要修改為new CipherB,setCipherB,)或添加一個新的加密算法CipherC(DataOperator中的encrypt方法需要添加ifelse、DataOperator類還要添加一個CipherC、main方法也需要修改),則需要修改客戶類Client和數據操作類DataOperator的源代碼,這違背了開閉原則。
在這里插入圖片描述
Client中的main方法:
在這里插入圖片描述

DataOperator中的setCipherA方法:
在這里插入圖片描述

DataOperator中的encrypt方法:
在這里插入圖片描述
現在使用里氏代換原則對其進行重構,使得系統(tǒng)可以靈活擴展,符合開閉原則。重構后的結構如圖所示,當需要修改加密算法時,可以直接需改配置文件;如果需要擴展加密算法,可以添加新的加密算法繼承CipherA類,然后修改Config配置文件就行,保證了對修改關閉對擴展開放??梢钥吹酵ㄟ^里氏代換原則確保了開閉原則。從而提高了系統(tǒng)的可維護性和可復用性。
在這里插入圖片描述
Client中的main方法:
在這里插入圖片描述

另外,里氏替換原則還可以用來判別兩個類是否應該為父子關系。下面看某公司給員工計算報酬的例子。其中{A}代表是一個抽象類。Employee是員工類,它是領月薪員工和領時薪員工的父類,Timecard是用來記錄時薪員工的小時數。Employee中的抽象方法calcPay方法用來計算工資,由各個子類負責具體實現。
在這里插入圖片描述
現在考慮如果要增加一個VolunteerEmployee志愿者員工類繼承至Employee類,即這類員工沒有薪水,那么calcPay該怎么實現
第一種方法,return 0:

在這里插入圖片描述

第一種方法返回return 0,但是這樣沒有意義,因為如果在其它地方有一個轉賬方法,那么它會給志愿者轉賬0元,沒有實際意義,志愿者打開手機銀行一看給我轉賬0元是什么意思?

第二種方法,拋異常:

在這里插入圖片描述

第二種方法拋異常。如果拋異常的話要么異常必須被捕獲,要么調用者說明,因此,在一個派生類上的約束已經影響到了基類用戶。

另外如果使用第二種方法,那原來的計算所有員工工資的代碼會這樣變動:
原來的代碼:

在這里插入圖片描述

變動后的代碼:
使用try catch語句

在這里插入圖片描述

或者
使用instaceof判斷是哪個類型,但這樣更糟糕,因為原來基于Employee基類的代碼,現在必須要明確引用它的一個子類VolunteerEmployee

在這里插入圖片描述

但不管哪樣變動,都影響到了其它地方。其根源在于違背了里氏替換原則,因為VolunteerEmployee不能和Employee是父子關系。如果是父子關系會違背里氏替換原則,VolunteerEmployee不能透明地替代Employee。只要當調用一個派生類上的方法時造成了非法使用,就會違反里氏替換原則;如果使用了一個退化的派生類的方法(什么也沒實現),也是違反里氏替換原則。此時說明該方法對派生類是無意義的。繼承應該是關于行為的,而不是志愿者員工從直覺上判斷就是員工類,而是從行為上來判斷是否屬于員工類。很明顯這里的員工類是計算薪水的員工,而志愿者員工不計算薪水,所以志愿者員工不應該繼承員工類。通過里氏替換原則可以幫助我們來判斷兩個類是否應該用繼承關系。

六、依賴倒轉原則(DIP) 6.1定義:

第四個原則,依賴倒轉原則。依賴倒轉原則有兩種方式的定義。

第一種定義是:高層模塊不應該依賴低層模塊,它們都應該依賴抽象。抽象不應該依賴于細節(jié),細節(jié)應該依賴于抽象。(High level modules should not depend upon low level modules, both should depend upon abstractions. Abstractions should not depend upon details, details should depend upon abstractions.)

第二種定義是:要針對接口編程,不要針對實現編程。(Program to an interface, not an implementation.)

6.2分析:

依賴倒轉原則是Robert C. Martin在1996年為《C++ Reporter》所寫的專欄Engineering Notebook的第三篇,后來加入到他在2002年出版的經典著作《Agile Software Development, Principles, Patterns, and Practices》中。也就是下面這個人和他寫的經典書籍。簡單來說,依賴倒轉原則就是指:代碼要依賴于抽象的類,而不要依賴于具體的類;要針對接口或抽象類編程,而不是針對具體類編程。依賴倒轉原則要求客戶端依賴于抽象耦合,以抽象方式耦合是依賴倒轉原則的關鍵。

在這里插入圖片描述

6.3舉例:

現在通過舉例來說明依賴倒置原則的應用。如圖中所示,現在代碼一共有三層,高層模塊Policy layer是策略層,中層模塊Mechanism Layer是機制層,它對策略層進一步實現,底層模塊Utility Layer是工具層,提供一些工具層的東西給中層模塊使用??梢钥吹剑邔诱{用了中層然后中層又調用了底層,越往下相對于上一層實現的越具體(上一層相當于抽象,下一層相當于具體,抽象依賴于具體)。這樣的設計看起來似乎是正確的,但實際上是不好的。因為高層模塊Policy layer對下面的兩個層的改動都很敏感,中層模塊對底層模塊的改動很敏感。如果底層模塊有改動,那么中層模塊可能也會隨之改動從而可能導致高層也會改動。
在這里插入圖片描述

現在我們使用依賴倒置原則對其進行重構。重新構造后的結構如圖所示。我們在每一層添加抽象化的接口,使下一層實現這個接口。這樣當下一層發(fā)生改變時,因為上一層和下一層中間的接口沒有發(fā)生改變所以不會影響到上一層,上一層只依賴于抽象的接口而不是下一層具體的實現。這樣就降低了模塊間的耦合,提高了系統(tǒng)的可維護性和可復用性。
在這里插入圖片描述

七、接口隔離原則(ISP) 7.1定義:

第五個原則,接口隔離原則。接口隔離原則有兩種方式的定義。

第一種定義是:客戶端不應該依賴那些它不需要的接口。(Clients should not be forced to depend upon interfaces that they do not use.)

第二種定義是:一旦一個接口太大,則需要將它分割成一些更細小的接口,使用該接口的客戶端僅需知道與之相關的方法。(Once an interface has gotten too ‘fat’ it needs to be split into smaller and more specific interfaces so that any clients of the interface will only know about the methods that pertain to them.)

7.2分析:

接口隔離原則是指使用多個專門的接口,而不使用單一的總接口。每一個接口應該承擔一種相對獨立的角色,不多不少,不干不該干的事,該干的事都要干。使用接口隔離原則拆分接口時,首先必須滿足單一職責原則,將一組相關的操作定義在一個接口中,且在滿足高內聚的前提下,接口中的方法越少越好??梢栽谶M行系統(tǒng)設計時采用定制服務的方式,即為不同的客戶端提供寬窄不同的接口,只提供用戶需要的行為,而隱藏用戶不需要的行為。

7.3舉例:

現在通過客戶系統(tǒng)來說明接口隔離原則的應用。如圖展示了一個擁有多個客戶類的系統(tǒng),在系統(tǒng)中定義了一個巨大的接口(胖接口)AbstractService來服務所有的客戶類??梢钥吹綄τ贑lienA類,AbstractService在提供operatorA方法的同時還提供了它不需要的operatorB和operatorC方法,對于ClienB類和ClienC類均是如此。顯而易見,這并不合理。因為一是接口的實現類龐大,實現類中需要實現接口中的所有方法,靈活性較差,如果某些方法不實現而是大量空方法,將導致系統(tǒng)中產生很多無用的代碼,影響代碼的質量。另外由于客戶端針對大接口編程,將在一定程度上破壞程序的封裝性,客戶端看到了不應該看到的方法,沒有為客戶端定制接口。這樣的設計結構違背了接口隔離原則。
在這里插入圖片描述

現在我們使用接口隔離原則對其進行重構??梢钥吹轿覀儗bstractService進行了分割,分割成了多個細小的接口。對于每一個客戶類,只需要依賴它需要的接口就行了。如此以來不同的客戶類使用不同的接口,只提供客戶類需要的行為,隱藏了客戶類不需要的行為。這樣的設計顯然是合理的。
在這里插入圖片描述

八、迪米特法則(LOD) 8.1定義:

接下來要介紹的是迪米特法則(Law of Demeter, LoD)又稱為最少知識原則(Least Knowledge Principle, LKP),它有多種定義方法,其中幾種典型定義如下。
第一種定義是不要和“陌生人”說話(Don’t talk to strangers.)。
第二種定義是只與你的直接朋友通信(Talk only to your immediate friends.)。
第三種定義是每一個軟件單位對其他的單位都只有最少的知識,而且局限于那些與本單位密切相關的軟件單位(Each unit should have only limited knowledge about other units: only units “closely” related to the current unit.)。

8.2分析:

簡單來說,迪米特法則就是指一個軟件實體應當盡可能少的與其他實體發(fā)生相互作用。這樣,當一個模塊修改時,就會盡量少的影響其他的模塊,擴展會相對容易,這是對軟件實體之間通信的限制,它要求限制軟件實體之間通信的寬度和深度。

在迪米特法則中,對于一個對象,其朋友包括以下幾類:
(1) 當前對象本身(this);
(2) 以參數形式傳入到當前對象方法中的對象;
(3) 當前對象的成員對象;
(4) 如果當前對象的成員對象是一個集合,那么集合中的元素也都是朋友;
(5) 當前對象所創(chuàng)建的對象。任何一個對象,如果滿足上面的條件之一,就是當前對象的“朋友”,否則就是“陌生人”。

在狹義的迪米特法則中,如果兩個類之間不必彼此直接通信,那么這兩個類就不應當發(fā)生直接的相互作用,如果其中的一個類需要調用另一個類的某一個方法的話,可以通過第三者轉發(fā)這個調用。下面這張圖的介紹請觀看視頻(在33分48秒處)
在這里插入圖片描述

迪米特法則的主要用途在于控制信息的過載:
1.在類的劃分上,應當盡量創(chuàng)建松耦合的類,類之間的耦合度越低,就越有利于復用,一個處在松耦合中的類一旦被修改,不會對關聯的類造成太大波及;
2.在類的結構設計上,每一個類都應當盡量降低其成員變量和成員函數的訪問權限;
3.在類的設計上,只要有可能,一個類型應當設計成不變類;
4.在對其他類的引用上,一個對象對其他對象的引用應當降到最低。

8.3舉例:

現在通過舉例來說明迪米特法則的應用。如圖展示了某系統(tǒng)界面類(如Form1、Form2等類)與數據訪問類(如DAO1、DAO2等類)之間的調用,可以從圖中看到它們的調用關系較為復雜。迪米特法則強調不要有太多的緊耦合而是應該是采用松耦合,一個軟件實體應當盡可能少的與其他實體發(fā)生相互作用??梢钥吹剑現orm3與DAO2-4這三個DAO都有關聯,其中有一個發(fā)生變換都會影響到Form3。另外DAO2發(fā)生改變除了會影響Form3還會影響Form4,Form5,所以下面的設計是一個不太好的設計。
在這里插入圖片描述
現在我們使用迪米特法則對其進行重構。重構的結果如圖所示??梢钥吹?,我們在Form和DAO的中間添加了一個中間層Controller,這樣就降低了系統(tǒng)的耦合。Form通過中間的Controller與DAO發(fā)生間接的通信。這樣當DAO發(fā)生改變時就不會影響到Form,達到了Form盡可能少的與其他實體發(fā)生相互作用的目的。
在這里插入圖片描述

九、合成復用口原則(CRP) 9.1定義:

最后一個原則,合成復用原則。合成復用的定義是盡量使用對象組合,而不是繼承來達到復用的目的。(Favor composition of objects over inheritance as a reuse mechanism.)

9.2分析:

合成復用原則就是指在一個新的對象里通過關聯關系(包括組合關系和聚合關系)來使用一些已有的對象,使之成為新對象的一部分;新對象通過委派調用已有對象的方法達到復用其已有功能的目的。簡言之:要盡量使用組合/聚合關系,少用繼承。因為通過繼承來復用,雖然實現簡單。但破壞系統(tǒng)的封裝性;從基類繼承而來的實現是靜態(tài)的,不可能在運行時發(fā)生改變,沒有足夠的靈活性;只能在有限的環(huán)境中使用。(“白箱”復用 )而通過組合/聚合來復用,可以使耦合度相對較低,選擇性地調用成員對象的操作;可以在運行時動態(tài)進行。(“黑箱”復用 )

9.3舉例:

現在舉例來說明接口隔離原則的應用。某教學管理系統(tǒng)部分數據庫訪問類設計如圖所示,可以看到StudentDAO和TeachearDAO通過繼承來復用DBUtil中的getConnection方法來鏈接數據庫,首先可以發(fā)現DBUtil和Student/TeachearDAO不是is-a的關系,也就是從語義來說不應該繼承關系。另外,如果需要更換數據庫連接方式,如原來采用JDBC連接數據庫,現在采用數據庫連接池連接,則需要修改DBUtil類源代碼。如果StudentDAO采用JDBC連接,但是TeacherDAO采用連接池連接,則需要增加一個新的DBUtil類,并修改StudentDAO或TeacherDAO的源代碼,使之繼承新的數據庫連接類,這將違背開閉原則,系統(tǒng)擴展性較差。
在這里插入圖片描述
現在我們使用合成復用原則對其進行重構。重構的結果如圖所示??梢钥吹竭@一次我們采用了聚合的方式來復用DBUtil。這樣一來當我們需要換數據庫鏈接方法時,可以創(chuàng)建一個新類NewDBUtil來繼承DBUtil從而在滿足開閉原則的前提下,對功能進行擴展??梢钥吹叫碌脑O計結構提高了系統(tǒng)的可維護性和可復用性。
在這里插入圖片描述

十、面向對象設計原則總結

七大原則本質上指導了兩件事情,第一件事情是一個類該如何設計,第二件事情是兩個類關系該如何設計。對于一個類該如何設計主要遵循單一職責原則,即類的職責要單一,不能將太多的職責放在一個類中,類的變化點要盡可能少和開閉原則,即軟件實體對擴展是開放的,但對修改是關閉的,即在不修改一個軟件實體的基礎上去擴展其功能。這兩個原則使得一個類滿足高內聚。對于2個類關系該如何設計,從策略上來講,最鼓勵我們去遵循的首先是迪米特法則,即兩個類盡量不要發(fā)生關系,要盡量少的去發(fā)生關系;如果非要發(fā)生關系,鼓勵遵循依賴倒置原則,要依賴抽象,和抽象發(fā)生關系而不是具體的類發(fā)生關系,即要針對抽象層編程,而不要針對具體類編程;接著就是,若發(fā)生依賴關系,要注意接口隔離原則,即,使用多個專門的接口來取代一個統(tǒng)一的接口,要依賴也僅僅依賴自己需要的服務;如果現在有復用的需要,應該優(yōu)先使用關聯關系而不是繼承,即遵循合成復用原則;如果關聯關系滿足不了要求,非要用繼承,那么此時就應該遵循里氏替換原則,即所有引用基類(父類)的地方必須能透明地使用其子類的對象。迪米特法則、依賴倒置原則、接口最小隔離原則、合成復用原則和里氏替換原則使得類之間滿足松耦合。
在這里插入圖片描述
在這里插入圖片描述

可見遵循面向對象設計的七大原則可以使我們的系統(tǒng)實現高內聚松耦合并且能夠提高系統(tǒng)的可維護性和可復用性,希望通過今天的分享能夠使得大家在今后利用面向對象語言編寫代碼時給大家?guī)硪恍椭沟迷谠O計系統(tǒng)時更合理,編寫代碼時質量更高,以上就是今天給大家分享的全部內容,感謝大家的閱讀。

你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧

當前文章:深入淺出精講面向對象設計七大原則,徹底領悟設計背后思想-創(chuàng)新互聯
文章來源:http://bm7419.com/article8/goiip.html

成都網站建設公司_創(chuàng)新互聯,為您提供電子商務、動態(tài)網站標簽優(yōu)化、定制開發(fā)企業(yè)網站制作、網站維護

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯

成都seo排名網站優(yōu)化