大家一起学面向对象设计模式系列Chapter 02 软件设计的基本原则
?????我們?yōu)槭裁匆褂迷O(shè)計(jì)模式呢?有人可能會說為了設(shè)計(jì)出"高內(nèi)聚低耦合"的軟件。"高內(nèi)聚低耦合"的軟件實(shí)際上也就是本文所說的具有可維護(hù)性和可復(fù)用性的軟件。
?????這篇文章主要講解兩方面內(nèi)容,這兩方面是軟件設(shè)計(jì)中很重要,也是很關(guān)鍵的內(nèi)容,希望大家認(rèn)真思考并深刻理解。第一部分就是關(guān)于軟件的可維護(hù)性和可復(fù)用性的相關(guān)內(nèi)容,第二部分就是在第一部分的基礎(chǔ)上逐條講解面向?qū)ο筌浖O(shè)計(jì)的基本原則,本文內(nèi)容都是些很理論性的東西,這些理論是軟件設(shè)計(jì)的基礎(chǔ)。凡是有理論的地方,就有如何恰當(dāng)?shù)膶⒗碚搼?yīng)用到實(shí)踐中去的問題,設(shè)計(jì)模式是對于學(xué)習(xí)OO設(shè)計(jì)原則的具體指導(dǎo),也就是說設(shè)計(jì)模式就是將這些理論應(yīng)用到實(shí)踐的一種成熟的方式。
?????軟件的可維護(hù)性和可復(fù)用性
?????首先來上一段大師所說的話,很經(jīng)典。
“通常認(rèn)為,一個易于維護(hù)的系統(tǒng),就是復(fù)用率較高的系統(tǒng);而一個復(fù)用率較高的系統(tǒng),就是一個易于維護(hù)的系統(tǒng)。但是實(shí)際上,可維護(hù)性和可復(fù)用性是兩個獨(dú)立的目標(biāo),就像兩只奔跑的兔子一樣,并不總是方向一致的。對于面向?qū)ο蟮能浖到y(tǒng)設(shè)計(jì)來說,在支持可維護(hù)性(Maintainability)的同時,提高系統(tǒng)的可復(fù)用性(Reuseability)是一個核心的問題。”--《Java與模式》閻宏博士
????? 軟件系統(tǒng)的可維護(hù)性:
?????軟件維護(hù)就是軟件的再生。一個好的軟件設(shè)計(jì),必須能夠允許新的設(shè)計(jì)要求以比較容易和平穩(wěn)的方式加入到已有的系統(tǒng)中去,從而使這個系統(tǒng)能夠不斷的的煥發(fā)出活力。一個可維護(hù)性較好的系統(tǒng),應(yīng)當(dāng)允許維護(hù)工作能夠以容易、準(zhǔn)確、安全和經(jīng)濟(jì)的形式進(jìn)行。
【導(dǎo)致可維護(hù)性較低的原因】
1、過于僵硬:在系統(tǒng)中加入一個新的功能,不管大小都很難,不僅意味著建造一個獨(dú)立的新的模塊,而且因?yàn)檫@個新功能會波及很多其他模塊,最后成跨越幾個模塊的改動。
2、過于脆弱:與軟件的過于僵硬同時存在,是軟件系統(tǒng)在修改已有代碼時過于脆弱。對一個地方的修改,往往會導(dǎo)致看上去沒有什么關(guān)系的另外一個地方發(fā)生故障。
3、復(fù)用率低:所謂復(fù)用,就是指一個軟件的組成部分,可以在同一個項(xiàng)目的不同地方甚至另一個項(xiàng)目中重復(fù)使用。復(fù)用率低,指當(dāng)一段代碼,函數(shù),模塊的功能可以在新的模塊或新的系統(tǒng)使用,但是已有代碼依賴于其他很多東西,很難分開。
4、黏度過高:一個改動可以保存原始設(shè)計(jì)意圖和原始設(shè)計(jì)框架的方式進(jìn)行,也可以以破壞原始意圖和框架進(jìn)行。第一種方法對系統(tǒng)的未來有利,第二種辦法是權(quán)宜之計(jì),可以解決短期的問題,但是會犧牲中長期的利益。如果一個系統(tǒng)中使用第二種方法比使用第一種方法容易,那么就是黏度過高。
【設(shè)計(jì)的目標(biāo)】
1、可擴(kuò)展性:新的性能可以很容易地加入到系統(tǒng)中去,就是可擴(kuò)展性。這就是系統(tǒng)“過于僵硬”的屬性的方面。
2、靈活性:可以允許代碼修改平穩(wěn)地發(fā)生,而不會波及到很多其他的模塊,這就是靈活性。靈活性其實(shí)就是“過于脆弱”的屬性的方面。
3、可插入性:可以很容易地將一個類抽出去,同時將另外一個有同樣接口的類加入進(jìn)來,這就是可插入性。其實(shí),這就是“黏度過高”的方面。
????? 軟件系統(tǒng)的可復(fù)用性:
【軟件復(fù)用的好處】
1、較高的生產(chǎn)效率;
2、較高的軟件質(zhì)量;
3、恰當(dāng)使用復(fù)用可以改善系統(tǒng)的可維護(hù)性。
【傳統(tǒng)的復(fù)用形式】
1、代碼的剪貼復(fù)用;
2、算法的復(fù)用;
3、數(shù)據(jù)結(jié)構(gòu)的復(fù)用。
【面向?qū)ο笤O(shè)計(jì)的復(fù)用】
在面向?qū)ο笳Z言中,數(shù)據(jù)的抽象化,繼承,封裝和多態(tài)性使得一個系統(tǒng)可以在更高層次上提供可復(fù)用性。數(shù)據(jù)的抽象化和繼承關(guān)系使得概念和定義可以復(fù)用;多態(tài)性使得實(shí)現(xiàn)和應(yīng)用得到復(fù)用;而抽象化和封裝可以保持和促進(jìn)系統(tǒng)的可維護(hù)性,復(fù)用的重點(diǎn)轉(zhuǎn)移到含有宏觀商業(yè)邏輯的抽象層次上。在面向?qū)ο蟮脑O(shè)計(jì)里面,可維護(hù)性復(fù)用是以設(shè)計(jì)原則和設(shè)計(jì)模式為基礎(chǔ)的。
?????提高系統(tǒng)可維護(hù)性和可復(fù)用性的設(shè)計(jì)原則
1、“開-閉”原則(Open-Closed Principle,或者OCP);
一個軟件實(shí)體應(yīng)該對擴(kuò)展開放,對修改關(guān)閉;
在設(shè)計(jì)一個模塊的時候,應(yīng)當(dāng)使這個模塊可以在不被修改的前提下被擴(kuò)展。換言之,應(yīng)當(dāng)可以在不必修改源代碼的情況下改變這個模塊的行為。這個原則實(shí)際上是對“對可變性的封閉原則“:找到一個系統(tǒng)的可變因素,將之封裝起來。這個原則意昧著兩點(diǎn):
1) 一個可變性不應(yīng)當(dāng)散落在代碼的很多角落里,而應(yīng)當(dāng)被封裝到一個對象里面。同一種可變性的不同表象意昧著同一個繼承等級結(jié)構(gòu)中的具體子類。
繼承就當(dāng)被看作是封裝變化的方法,而不應(yīng)當(dāng)被認(rèn)為是從一般的對象生成特殊對象的方法。
2) 一種可變性不應(yīng)當(dāng)與另一種可變性混合在一起。(所有類圖的繼承結(jié)構(gòu)一般不會超過兩層,不然就意昧著將兩種不同的可變性混合在了一起。)
這個原則是總的原則,其它幾條是這個原則的手段和工具。
2、里氏替代原則(Liskov Substitution Principle,或者LSP);
如果對于每一個類型為T1的對象o1,都有類型為T2的對象o2,使得以T1定義的所有程序P在所有的對象o1都代換成o2時,程序P的行為沒有變化,那么類型T2是類型T1的子類型。
換言之,一個軟件實(shí)體如果使用的是一個基類的話,那么一定適用于其子類,而且它根本不能察覺出基類對象和子類對象的區(qū)別。
反過來代換不成立。
3、依賴倒轉(zhuǎn)原則(Dependency Inversion Principle,或者DIP);
要依賴于抽象,不要依賴于具體。
開閉原則是目標(biāo),而達(dá)到這一目標(biāo)的手段是依賴倒轉(zhuǎn)原則。
抽象層次包含的是應(yīng)用系統(tǒng)的商務(wù)邏輯和宏觀的、對整個系統(tǒng)來說重要的戰(zhàn)略性決定,是必然性的體現(xiàn),那么抽象層次就應(yīng)當(dāng)是較為穩(wěn)定的,應(yīng)當(dāng)是復(fù)用的重點(diǎn);也應(yīng)當(dāng)是維護(hù)的重點(diǎn);而具體層次則含有一些次要的與實(shí)現(xiàn)有關(guān)的算法和邏輯,以及戰(zhàn)術(shù)性的決定,帶有相當(dāng)大的偶然性選擇。具體層次的代碼是會經(jīng)常有變動的,不能避免出現(xiàn)錯誤。
4、接口隔離原則(Interface Segregation Principle,或者ISP);
使用多個專門的接口比使用單一的總接口要好。
換言之,從一個客戶類的角度講:一個類對另一個類的依賴性應(yīng)當(dāng)是建立在最小的接口上的。
接口隔離原則與迪米特法則(下面講到)都是對一個軟件實(shí)體與其他的軟件實(shí)體的通信限制。迪米特原則要求盡可能地限制通信的寬度和深度,接品隔離原則要求通信的寬度盡可能地窄。這樣做的結(jié)果使一個軟件系統(tǒng)在功能擴(kuò)展過程當(dāng)中,不會將修改的壓力傳遞到其他對象。
一個接口相當(dāng)于劇本中的一種角色,而此角色在一個舞臺上由哪一個演員來演則相當(dāng)于接口的實(shí)現(xiàn)。因此,一個接口應(yīng)當(dāng)簡單地代表一個角色,而不是多個角色。如果系統(tǒng)涉及到多個角色的話,那么每一個角色都應(yīng)當(dāng)由一個特定的接口代表。
5、組合/聚合復(fù)用原則(Composition/Aggregation Principle,或者CARP);
組合/聚合原則就是在一個新的對象里面使用一些已有的對象,使之成為新對象的一部分;新的對象通過向這些對象的委派達(dá)到得復(fù)用已有功能的目的。
要盡量使用組合/聚合,盡量不要使用繼承。
6、迪米特法則(Law of Demeter,或者LoD);
一個軟件實(shí)體應(yīng)當(dāng)盡可能少的與其他實(shí)體發(fā)生相互作用。模塊之間的交互要少。這樣做的結(jié)果是當(dāng)系統(tǒng)的功能需要擴(kuò)展時,會相對更容易地做到對修改的關(guān)閉。一個對象應(yīng)當(dāng)對其他對象有盡可能少的了解。
7、單一職責(zé)原則(Single Responsibility Principle,或者SRP)
在設(shè)計(jì)中為每種職責(zé)設(shè)計(jì)一個類,彼此保持正交,互不干涉。這個原則比較容易理解,這里不在多說。
?????小結(jié)
?????當(dāng)我們掌握了C#的語法,當(dāng)我們了解了面向?qū)ο蟮姆庋b、繼承、多態(tài)等特性,當(dāng)我們可以用各種框架與技術(shù)構(gòu)建桌面以及Web應(yīng)用時,這并不意味著我們可以寫出面向?qū)ο蟮某绦?#xff0c;不意味著我們可以很好的實(shí)現(xiàn)代碼復(fù)用,彈性維護(hù),不意味著我們可以實(shí)現(xiàn)在維護(hù)、擴(kuò)展基礎(chǔ)上的代碼復(fù)用。使用面向?qū)ο笳Z言開發(fā)的程序不一定是面向?qū)ο蟮?#xff0c;使用面向過程的語言開發(fā)的程序也不一定不是面向?qū)ο蟮摹R腴_發(fā)出一個具有可維護(hù)性和可復(fù)用性的軟件系統(tǒng),那是需要優(yōu)秀的設(shè)計(jì)和長時間的運(yùn)行才能完成的,其實(shí)我們可以觀察一下,任何一個優(yōu)秀的軟件產(chǎn)品都是經(jīng)過長時間的設(shè)計(jì),運(yùn)行,維護(hù),修改等最后才成為成功的產(chǎn)品,版本上也在不斷的更新。衡量一個軟件開發(fā)者是不是一個好的軟件開發(fā)者,不是看他是否實(shí)現(xiàn)了軟件的必要功能,而是要看你的軟件在滿足功能需求的情況下是否做到了復(fù)用性和可擴(kuò)展性,這對于一個大型系統(tǒng)尤其重要。我們不要靜止的看待一個軟件,而一定要把軟件過程放在時間軸上來觀察與設(shè)計(jì)它,只有放在時間軸上經(jīng)得住考驗(yàn)的軟件系統(tǒng)才是成功的。軟件的復(fù)用性和可擴(kuò)展性對于大型系統(tǒng)是必要的,我們在設(shè)計(jì)自己的軟件系統(tǒng)時,甚至在編寫代碼時更需要考慮一下這樣做是否遵循了系統(tǒng)設(shè)計(jì)的原則,是否有利于系統(tǒng)的可維護(hù)性和可復(fù)用性,是否達(dá)到了常說的“高內(nèi)聚低耦合”呢?設(shè)計(jì)模式正是解決這一問題的王道。
?????從下文開始我們將結(jié)合實(shí)例對于GoF23種設(shè)計(jì)模式進(jìn)行一一講解。
?????Welcome to share your idea,thank you!歡迎分享您的想法,謝謝!
?????大家一起學(xué)面向?qū)ο笤O(shè)計(jì)模式系列 索引貼
轉(zhuǎn)載于:https://www.cnblogs.com/Thriving-Country/archive/2009/03/13/1408030.html
總結(jié)
以上是生活随笔為你收集整理的大家一起学面向对象设计模式系列Chapter 02 软件设计的基本原则的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL SERVER 优化 50法
- 下一篇: 任天堂新音樂遊戲上市