回歸最本質的,追求最基礎的!發現軟體世界那些不變的真理!
什麼是原則?
原則是指經過長期經驗總結所得出的合理化的現象。 ——百度百科
原則具有指導性、適用性、異樣性。
指導性:在猶豫要不要做某件事情的時候,可以根據自身的原則出發作出抉擇,所以 瑞·達利歐 根據自己的行為標出了一本書《原則》。
適用性:人在社會群體中分工合作實現自我生存和推動社會發展,在這個漫長的過程中,逐漸形成了一些人們對於言行的共識,例如欠債還錢,殺人償命等。
異樣性:每個人對某件事或某個觀點、態度的原則不同。比如股民會根據自己對股票的理解、市場的觀察以及自身的認知,產生不同的操作原則。
為什麼要學軟體設計原則?
軟體設計原則沒有銀彈,均是在代碼開發過程中總結出來的規律,而不是自然存在的真理。
學習設計原則,就像學習交通規則一樣。如果編碼比喻為開車,那設計原則就相當於交通規則。要想讓自己的軟體在市場上生存,就需要讓自己的車在道路上遵守交通規則。
通過交通原則的學習,才能靈活地完成剎車、停車、轉向燈、變道等各種各樣複雜的社會場景。同樣的,通過軟體設計原則的學習,才能靈活地設計出抽象、聚合、耦合、健壯的代碼來滿足各種各樣的業務場景。
如果用一句話總結:寫出優雅的、健壯的、可運行的程序!
所以在學習設計原則和編碼的時候,我們就應該多想一點:這樣寫夠不夠優雅?這樣寫夠不夠健壯?如果答案是肯定的,那就已經是最好的設計了。
軟體設計原則有哪些?
面向對象設計5個基本原則
2009年的時候,一個叫羅伯特·C·馬丁的哥們在一次大會上提出了SOLID的概念,即:
單一職責原則(Single responsibility principle,SRP)、
開閉原則 (The Open/Closed Principle, OCP) 、
里氏替換原則(Liskov Substitution principle)、
介面隔離原則(Interface-segregation principles,ISP)、
依賴反轉原則(Dependency inversion principle,DIP)。
注意只是這哥們提出的SOLID的概念,而不是這哥們創造的這5個原則。這些原則在之前已經存在,而他是將這些原則整合了起來。就像喬布斯只是將手機、MP3和相機整合起來,做出了IPhone,而不是喬布斯創造了智能手機。
這裡多提一下羅伯特·C·馬丁,這哥們是一位世界級軟體開發大師、設計模式和敏捷開發先驅。他在2010年出版了《代碼整潔之道》一書,這本書一經面世,就在軟體開發行業掀起了軒然大波 。小編最近還重刷了一遍,12年前的規範在計算機世界依然適用而不落俗套,是多麼的難能可貴。
再看一下這哥們出版的圖書,在豆瓣上的評分:
可以看到他出品的圖書的評分都相當的高,足以見得其實力非凡!
單一職責原則(Single responsibility principle,SRP)
這個原則是由馬丁先生在他的《敏捷軟體開發,原則,模式和實踐》一書中給出的。不過也是建立在巨人的肩膀之上產生的,說白了就是我們軟體工程師常說的:高內聚!這裡最抽象的是什麼是職責?馬丁先生的定義是"改變的原因"。
例子:
可以想像一下我們現實生活中製作一個報表。我們改變它有兩個原因:
1、報表內容的可以編輯,比如修改、格式化等功能
2、報表格式可以改變,比如轉為PDF、列印等功能
單一功能原則認為這兩方面的問題事實上是兩個分離的功能。這樣我們在設計的時候,應該設計到兩個不同的類或模塊里,從而做到每個類或模塊只有一個功能。
這樣做有什麼好處呢?
想像一下,如果不分開的話。我們修改了報表的內容,我們會擔心列印功能可能會不好使嗎?同樣我們列印了報表,會擔心報表的內容不正確嗎? 顯然不會,那就是因為我們的編輯部影響列印,我們的列印也不影響編輯,從而可以讓軟體更健壯。
開閉原則 (The Open/Closed Principle, OCP)
這個原則是伯特蘭·邁耶在他1988年發行的《面向對象軟體構造》中給出。馬丁先生1996年發表的文章《開閉原則》是使用這種方法的啟發式著作。 這個原則的核心是:
一旦完成了,除了錯誤的情況下再修改,否則都通過拓展的方式完成新的功能。
簡單地說就是:
對拓展開放,對修改關閉。
例子:
我們要發送通知。比如現在有了郵件通知,現在要添加電話通知。我們如果在原有的通知上修改的話,我們就可能會影響到之前的郵件通知,這樣就帶來了風險。 所以我們不在原來的通知上修改,而是拓展新的通知方式,有需要的可以調用新的通知方式。這樣就規避了原有業務的風險。
但是我們如何能夠對接上新的通知呢?這就要求很高的抽象能力。比如郵件通知需要郵箱號碼,電話通知需要電話號碼,甚至通知的形式和內容也不一樣。 如果上層做了很好的抽象,通知的發送邏輯各自實現,可以做到很優雅自如的表現。就像我們無論是坐火車、還是坐飛機,我們只需要人過去就可以乘坐一樣。
里氏替換原則(Liskov Substitution principle)
它由芭芭拉·利斯科夫(Barbara Liskov)在1987年在一次會議上名為「數據的抽象與層次」的演說中首先提出。所以被命名為Liskov Substitution principle。
所謂的里氏替換,本質上具體能代替抽象,兒子擁有父親的所有能力(父親的錢兒子能花)。
例子:
一個工廠招工,那這時候男工、女工都可以參與;如果一個工廠招女工,那這時候男工就不能參與,而女工就可以參與;如果一個工廠招青年女工,那這時候年齡大的女工不可參與等等。
那為什麼要這樣設計呢?這就涉及到計算機軟體需要遵守的另一個特性:健壯性!在實際項目中,每個子類對應不同的業務含義,使用父類作為參數,傳遞不同的子類從而完成不同的業務邏輯。
介面隔離原則(Interface-segregation principles,ISP)
我們每個人都喜歡簡潔,我需要的你給我,我不需要的你帶走。同樣在程序的世界裡也是一樣的。如果做到這種簡潔呢?就需要介面隔離。
例子:
我只想走路,你就給我一雙鞋就行了;我想騎車,你就只給我自行車就夠了。如果我既想走路,又想騎車,那就給我一雙鞋和一輛自行車。
這樣我們就做到了,不想要的無需關注,從而達到了一種隔離的效果。進而讓軟體之間解耦。
介面隔離原則(ISP)的目的是系統解開耦合,從而容易重構,更改和部署。
依賴反轉原則(Dependency inversion principle,DIP)
依賴反轉原則由羅伯特·C·馬丁提出,並且在數篇公開著作中被表述,包括論文《面向對象設計質量標準:對於依賴的分析》,以及一篇1996年出現在C++報道中的名為《依賴反轉原則》的文章,和《敏捷軟體開發,原則,模式和實踐》,《C#中的敏捷原則,模式和實踐》兩本書。
例子:父親需要依賴兒子的某項能力,但理論上父親不能直接調度兒子(比如:兒子還沒出生或兒子還未成年),那這時候父親將這個能力就行抽象化,等兒子長大了來把這個抽象具體實現了。這就是所謂的依賴反轉。
該原則規定:
高層次的模塊不應該依賴於低層次的模塊,兩者都應該依賴於抽象介面。 抽象介面不應該依賴於具體實現。而具體實現則應該依賴於抽象介面。
其他設計原則
迪米特法則 (Law of Demeter,LoD)
迪米特法則 (Law of Demeter,縮寫LoD)亦被稱作「最少知識原則(Principle of Least Knowledge)。這個原理的名稱來源於希臘神話中的農業女神,孤獨的迪米特。該原則是美國東北大學在1987年末在發明的,可以簡單地以下面任一種方式總結:
每個單元對於其他的單元只能擁有有限的知識:
只是與當前單元緊密聯繫的單元; 每個單元只能和它的朋友交談:
不能和陌生單元交談;
只和自己直接的朋友交談。
總之如果用現代的話就是:專業的人做專業的事,集中注意力辦大事!
例子:
人可以命令一條狗行走,但是不應該直接指揮狗的腿行走,應該由狗去指揮控制它的腿如何行走。
迪米特法則使得軟體更好的可維護性與適應性。因為對象較少依賴其它對象的內部結構,可以改變對象自身的實現而不用改變它的調用者。
不要重複自己(Don't repeat yourself,DRY)
DRY(干)的原則是「系統中的每一部分,都必須有一個單一的、明確的、權威的代表」。其反例為WET(濕),其有多種全稱,包括「Write everything twice」(把每個東西寫兩次)、「We enjoy typing」(我們就是喜歡打字)或「Waste everyone's time」(浪費大家的時間)。
例子:
比如人用腿走路,這時候我們如果有多個地都寫了人用腿走路,如果突然人進化了,還可以用手走路。這時候就需要改多處,才能實現。從而增加了工作量和不可控因素。
但是有時候為了可讀性,或避免耦合,或過早重構,或開發效率,應放棄DRY原則。
設計原則是一種規範,或是一種指導。真實的場景不見得必須要使用過設計原則。就像寫一首五言律詩,在不遵守原則的情況下能寫出沁人心脾、攝人心魄的詩也是值得敬仰的。
結語
除了以上提到的原則,還有很多原則,比如包括:
KISS原則(Keep It Simple, Stupid):其本質是追求簡潔、易於維護,和單一職責原則類似。
YAGNI 原則(You Ain』t Gonna Need It):程序員應該在面臨確鑿的需求時,才實現相應功能,意在不要過度設計。
原則可能多種多樣,其目的只有一個:寫出高質量的代碼!
在實際工作中,不要迷信原則,畢竟原則也是為了讓工作更輕鬆,如果一味迷信成為負擔了,那就本末倒置、得不償失了。