系列文章目錄
文章目錄
- 系列文章目錄
- 一、單一職責原則
- 方塊游戲的設計
- 二、開放-封閉原則
- 原則介紹
- 何時應對變化
- 三、依賴倒轉原則
- 依賴倒轉原則介紹
- 里氏代換原則
- 總結
一、單一職責原則
單一職責原則,聽字面意思,就是說功能要單一,他的準確解釋是,就一個類而言,應該僅有一個引起他變化的原因,我們在做編程的時候,很自然的就會給一個類加各種各樣的功能,比如我們寫一個窗體應用程序,一般都會生成一個Formal這樣的類,于是我們就把各種各樣的代碼,像某種商業運算的算法,或者數據庫訪問的SQL語句什么的都寫進到這樣的類中,這就意味著,無論任何需求要來,你都需要修改這個窗體類,這其實是很糟糕的,維護麻煩,復用不可能,也缺乏靈活性。
單一職責原則:就一個類而言,應該僅有一個引起他變化的原因。
方塊游戲的設計
我們這里通過手機里的俄羅斯方塊這款游戲為例,開發這個小游戲,我們應該怎么做呢?
我們可以先建立一個窗體,然后加一個用于游戲框的控件,一個按鈕Button來控制‘開始’,最后計時器控制用于分時動畫的編程,寫代碼當然就是編寫計時器時間來繪出和刪除方塊,并做出堆積和消層的判斷,再編寫控件的鍵盤事件,如左箭頭左移,右箭頭右移等。這里我們思考,如果把所有的代碼都寫在了窗體這個java類里面,其實這樣是不合理的,因為如果這樣的話,如果要開發其他版本的俄羅斯方塊,或者是Web版或者Windows窗臺版的俄羅斯方塊,那現在這個代碼其實是不好復用的!
但這當中,有些東西是始終沒變的,比如說下落、旋轉、碰撞判斷、移動堆積這些游戲邏輯。這些都是和游戲有關的邏輯,和界面如何表示沒有什么關系,為什么要寫在一個類里面呢?如果一個類承擔的責任過多,就等于把這些職責耦合在一起,一個職責的變化可能會削弱或者抑制這個類完成的其他職責的能力。這種耦合會導致脆弱的設計,當變化發生時,設計會遭受到意想不到的破壞。 所以,我們應該找出那些是界面,那些是游戲邏輯,然后進行分離。
軟件設計真正要做的許多內容,就是發現職責并把那些職責相互分離。 其實要去判斷是否應該分離出來類,也不難,那就是如果你能夠想到多余一個的動機去改變一個類,那么這個類就具有多于一個的職責 。
二、開放-封閉原則
原則介紹
開放-封閉原則,是說軟件實體(類、模塊、函數等)應該可以擴展,但是不可修改 。
這個原則其實是有兩個特征,一個是說‘對于擴展是開放的’ , 另一個是說‘對于修改是封閉的’ 。
我們在做任何系統的時候都不要指望系統一開始時需求綁定,就再也不會變化,這是不現實也不科學的想法,需求是一直變化的,那么如何在面對需求的變化時,設計的軟件可以相對容易修改,不至于說,新需求依賴,就要把整個程序推倒重來。怎樣的設計才能面對需求的改變卻可以保持相對穩定,從而使得系統可以在第一個版本以后不斷推出新的版本呢? 開放-封閉給了我們答案。設計軟件要容易維護又不容易出問題的最好的辦法就是多擴展,少修改。
何時應對變化
開放–封閉原則的意思就是說,你設計的時候,時刻要考慮,盡量讓這個類足夠好,寫好了就不要去修改了,如果新需求來,我們增加一些類就完事了,原有的代碼能不動則不動,但是,絕對的對修改關閉是不可能的,無論模塊是多么的‘封閉’,都會存在一些無法對之封閉的變化。既然不可能完全封閉,設計人員必須對于他設計的模塊應對出哪種變化封閉做出選擇。他必須先猜測出最有可能發生的變化種類,然后構造抽象來隔離那些變化。
但是,事先猜測是很難做到的,但我們卻可以在發生小變化時,就及早去想辦法,應對發生更大變化的可能,也就是說,等到變化發生時立即采取行動,在我們最初編寫代碼時,假設變化不會發生,當變化發生時,我們就創建抽象來隔離以后發生的同類變化
我們在簡單工廠模式中,一開始只有一個加法程序,后面我們需要增加一個減法功能,我們發現,增加功能需要修改原來這個類,這就違背了今天所講到的‘開放-封閉’ 原則,于是你就該考慮重構程序,增加一個抽象的運算類,通過一些面向對象的手段,如繼承、多態等來隔離具體加法、減法與client耦合,需求依然可以滿足,還能應對變化,這時我們再加乘除法功能,就不需要再去更改client類了二十增加乘法和除法的字類就可,即面對需求,對程序的改動是通過增加新代碼進行的,而不是更改現有的代碼,這就是開放–封閉原則 的精神所在。
當然,并不是什么時候應對變化都是容易的,我們希望的是在開發工作展開不久就知道可能發生的變化,查明可能發生的變化所等待的時間越長,要創建正確的抽象就越困難。
開放封閉原則是面向對象設計的核心所在。遵循這個原則可以帶來面向對象技術所聲稱的巨大好處,也就是可維護、可擴展、可復用、靈活性好。開發人員應該僅對程序中呈現出頻繁變化的那些部分做出抽象,然而對于應用程序中的每個部分都刻意地進行抽象同樣不是一個好主意。拒絕不成熟的抽象和抽象本身一樣重要。
三、依賴倒轉原則
依賴倒轉原則介紹
依賴倒轉原則,原話解釋是抽象不應該依賴細節,細節應該依賴于抽象,說簡單點,就是要針對接口編程,不要對實現編程
依賴倒轉原則
(1)高層模塊不應該依賴低層模塊。兩個都應該依賴抽象。
(2)抽象不應該依賴細節。細節應該依賴抽象。
那么為什么要叫倒轉呢?
在面向過程開發時,為了使得常用代碼可以復用,一般都會把這些常用代碼寫成許許多多函數的程序庫,這樣我們在做新項目時,去調用這些低層的函數就可以了。比如我們做的項目大多要訪問數據庫,所以我們就把訪問數據庫的代碼寫成了函數,每次做新項目時就去調用這些函數。這也就叫做高層模塊依賴低層模塊。
其實問題也就出在這里,我們做新項目時,返現業務邏輯的高層模塊都是一樣的,但客戶卻希望使用不同的數據庫或者儲存信息方式,這時就出現麻煩了。我們希望能再次利用這些高層模塊,但高層模塊都是與低層的訪問數據庫綁定在一起的,沒辦法復用這些高層模塊。這里我們以電腦舉例,電腦里如果CPU、內存、硬盤都需要依賴具體的主板,主板一壞,所有的部件就都沒用了,這顯然不合理,反過來,如果內存壞了,也不應該造成其他部件不能用才對。而如果不管高層模塊還是低層模塊,他們都依賴于抽象,具體一點就是接口和抽象類,只要接口是穩定的,那么任何一個更改都不用擔心其他受到影響,這就使得無論高層模塊還是底層模塊都可以很容易地被復用。
如果這里還不是很理解,也是很正常的,因為還有一個設計原則,讓我們產生困惑。這個原則就叫里氏代換原則
里氏代換原則
里氏代換原則: 一個軟件實體如果使用的是一個父類的話,那么一定適用于其子類,而且它察覺不出父類對象和子類對象的區別。也就是說,在軟件里面,把父類都替換成它的子類,程序的行為沒有變化
里氏代換原則: 子類型必須能夠替換掉它們的父類型。
這里貌似是繼承需要理解的概念,子類繼承了父類,所以子類可以以父類的身份出現。
小問題:如果在面向對象設計時,一個是鳥類,一個是企鵝類,如果鳥是可以飛的,企鵝不會飛,那么企鵝是鳥嗎?企鵝可以繼承鳥這個類嗎?
其實這里是不可以的,我們討論的是面向對象設計時,也就是說,子類擁有父類所有非private的行為和屬性。鳥會飛,但是企鵝不會飛。所以這里企鵝不能以父類–鳥的身份出現,因為前提說所有鳥都可以飛,而企鵝飛不了,所以企鵝不可以繼承鳥類。
所以,只有當子類可以替換掉父類,軟件單位的功能不受到影響時,父類才能真正被復用,而子類也能夠在父類的基礎上增加新的行為。
正是由于子類型的可替換性才使得使用父類類型的模塊在無須修改的情況下就可以擴展 。
依賴倒轉其實可以說是面向對象設計的表示,用哪種語言來編寫程序不重要,如果編寫時考慮的都是如何針對抽象編程而不是針對細節編程,即程序中所有的依賴關系都是終止于抽象類或者接口,那就是面向對象的設計,反之那就是過程化的設計了
總結
以上就是本文全部內容,本文主要向大家介紹了設計模式中的三大原則-----單一職責原則、開放-封閉原則、依賴倒轉原則。感謝各位能夠看到最后,如有問題,歡迎各位大佬在評論區指正,希望大家可以有所收獲!創作不易,希望大家多多支持!
最后,大家再見!祝好!我們下期見!