軟件設計原則能夠說是無數前輩在踩過無數坑以後總結出來的提醒後人遵循的一些基本思想、規範、模式。遵循這些原則,有利於咱們作出良好的設計,好比達到高內聚低耦合、模塊劃分清晰、源碼可讀性可維護性良好的效果。下面將對最廣爲人知的八大原則進行說明,有些原則還會給出代碼示例。前端
6.1 KISS原則ajax
KISS是「keep it simple, stupid」的簡稱,這種觀點認爲,一個簡單的系統每每比複雜的系統運轉得更好,所以,在進行系統設計時應儘可能保持簡單,避免沒必要要的複雜性。 編程
這裏強調的是沒必要要的複雜性,有時候一些複雜性不可避免,但咱們不管在產品設計仍是架構設計方面,在保持功能完整性的同時,應該儘可能作減法,堅守KISS原則。後端
6.2 DRY原則設計模式
DRY是「Don't repeat yourself 」的簡稱,這個原則的目標在於經過抽象的手段來減小重複的模式,避免冗餘,包括設計、代碼等方面的冗餘,強調系統中的每一個實體元素都是單一的、無歧義的。DRY原則運用好的話,系統中任何元素的修改都不會致使邏輯上跟它無關的元素的修改,而邏輯上相關的元素即便被修改,也是以統一的可預測的方式被修改。服務器
怎麼作到遵照DRY原則呢?本人認爲要依靠抽象思惟,咱們在設計系統和數據結構時,儘可能理解透徹系統中所存在的實體及其關係,將共性的內容抽出來成爲一個抽象層,具體的實體再從抽象層派生,這裏其實就對應了面向對象裏面繼承的概念,繼承使得代碼能夠被複用。數據結構
6.3 開閉原則架構
開閉原則也叫Open-Close原則,大體思想是:軟件實體(包括類、模塊、函數等)應該對擴展開放,而對修改關閉。以類爲例來講明,就是你能夠從一個基類派生新的類做爲子類,子類能夠擴展基類的功能,但不能修改基類的代碼。開閉原則也是最基本的原則,這一章中全部其它原則自己都遵照了開閉原則。框架
現實中,不少軟件中的插件,就是開閉原則思想的具體實踐。一般容許你經過添加插件的方式來擴展軟件的行爲,而不容許修改軟件的一些基礎功能。若是容許你修改軟件的基本功能,那麼有一天,這個軟件具有的功能和軟件原來聲稱的功能截然不同,想一想都以爲是件詭異的事情。前後端分離
6.4 里氏替換原則
里氏替換原則(Liskov substitution)能夠表述爲:全部出現基類的地方均可以由子類來代替,而且替換後不須要修改其它代碼系統還能夠繼續正常工做。這樣看來,里氏替換原則也符合開閉原則,不修改基類,而是將子類替換基類,就可以達到擴展系統功能的目的。
怎麼運用這個原則呢?我的認爲在設計系統時,要關注系統實體間的關係(好比是不是繼承關係)和擴展性,這兩個特性結合起來的地方可能就是使用了里氏替換原則。
6.5 依賴倒置原則
依賴倒置原則是軟件模塊解耦的一種方式,其核心思想是:高層模塊不該該依賴於底層模塊,它們都應該依賴於抽象,也就是抽象不能依賴於細節,細節應該依賴抽象。
先後端分離架構就是一個例子,前端只管使用ajax請求服務端的API,不在意服務器端API服務是如何實現和部署的,只須要API接口遵照協議(好比HTTP)就行了。
6.6 單一職責原則
顧名思義,單一職責原則的核心思想是:一個類,只作一件事情,只有一個理由引起它的改變。這也和Unix的設計哲學之一「Do One Thing and Do It Well」有殊途同歸之妙,即只作一件事,並把它作好。
這個原則提及來最簡單,而實際上執行起來不容易,稍微不當心就容易違背它。只作一件事,對應到軟件設計裏邊,就是一個模塊(類、函數)儘可能少作事情,但要作好,這樣也符合咱們常說的高內聚低耦合的設計要求,因此在單一原則裏邊,咱們須要注意的是模塊(類、函數)的邊界和職責劃分,思考怎樣劃分才能符合該原則,這裏就不舉例子了。
6.7 接口隔離原則
接口隔離原則是面向對象設計的一個原則,倡導將接口分離,即用戶不須要實現他使用不到的接口。好比一個接口定義有兩個方法:
interface ShapeInterface {
public function area();
public function volume();
}
而有時候實現類只使用到其中一個方法,但編程語言規範又迫使派生類去實現基類的兩個接口。若是遵循接口隔離原則,這時候應該將接口分解爲兩個接口,而後實現類根據須要能夠只實現其中一個接口,若是須要兩個接口方法都實現,就去實現兩個接口好了。代碼以下:
interface ShapeInterface {
public function area();
}
interface SolidShapeInterface {
public function volume();
}
class Cuboid implements ShapeInterface, SolidShapeInterface {
public function area() { }
public function volume() {}
}
原則是一種思想,並不侷限於某種編程語言,上面以Java代碼爲例來講明,其餘語言中能夠根據各個語言的不一樣規範採用不一樣的方式來是接口符合這個原則。
6.8 最少知識原則
最少知識原則(Least Knowledge Principle)也叫迪米特法則(Law of Demeter),其來源於1987年荷蘭大學的一個叫作Demeter的項目。Craig Larman把Law of Demeter又稱做「不要和陌生人說話」,其核心思想是提倡一個模塊只知道本身模塊內部的東西,對其它模塊知之甚少,與其它模塊的交互都是經過接口來實現,這個原則能夠引導咱們完成低耦合的系統設計。
上面說到的是模塊,那其實咱們能夠小到一個類,一個函數,均可以遵循最少知識原則。好比咱們儘可能將類的成員變量聲明爲私有的,只能經過類的公共方法來訪問該變量,外部不能直接使用該變量。在函數裏面,咱們儘可能使用局部變量,少用全局變量,由於局部變量只在這個函數內有效,全局變量能夠共用,使得函數的耦合性變高了。所以,提倡使用局部變量,也是遵循了最少知識原則。
6.9 好萊塢明星原則
好萊塢明星原則叫IOC(Inversion of control)原則或者控制反轉原則,英文裏比較形象的說法就是「Don’t call me, I will call you back」,源於這麼一個現象:好萊塢的經紀人們通常不但願你去聯繫他們,而是他們會在須要的時候來聯繫你,由於主動權確實是掌握在他們手上,耍大牌不用商量。
傳統的編程方式是,用戶代碼直接調用底層庫函數,而控制反轉原則是底層框架反過來調用用戶編寫的代碼,相似基於事件的編程。當事件觸發時,底層框架代碼被調用,而後再反過來調用用戶自定義的事件處理程序。這樣來看的話,就是框架提供了程序的引擎和接口定義,用戶代碼負責接口實現,應用程序的開發模式就掌控在框架開發者的手中。引用臺灣著名架構師高煥堂的話,就是好萊塢明星原則保證了強盛,保證了底層框架的龍頭地位。
這裏咱們舉個簡單的例子吧,好比咱們在進行GUI編程時,一般要爲控件編寫一個OnCreate函數,可是這個函數咱們從沒有主動去調用它,而是框架在適當的時機來調用,這就是將控制權交給了底層框架,完成了控制反轉。
6.10 面向接口原則
面向對象設計模式中有一個模式叫橋接模式(Bridge pattern),提倡基於接口編程,英文裏邊的說法是:Program to an interface, not an implementation。由於同一個接口能夠衍生出各類不一樣的實現,接口和實現分離使得用戶程序能夠根據不一樣的狀況選擇不一樣的實現,實現的修改獨立於接口的調用者,這樣當須要修改實現代碼時,接口調用者是無感知的,這樣也就下降了軟件的耦合度。
下面咱們以Java代碼爲例來看一下如何面向接口編程,首先,咱們有一個顯示接口,定義以下:
interface displayModule {
public void display();
}
顯示器類,實現displayModule接口
public class Monitor implements displayModule{
public void display() {
System.out.println(「Display through Monitor」);
}
}
投影儀類,實現displayModule接口
public class Projector implements displayModule
{
public void display(){
System.out.println(「Display through projector」);
}
}
主機類,聚合了顯示接口
public class Computer
{
// 面向接口編程
displayModule dm;
Public void setDisplayModule
(displayModule dm)
{
this.dm=dm;
}
public void display()
{
dm.display();
}
}
程序主函數,相似於一個裝配器
public static void main(String args[])
{
Computer cm = new Computer();
displayModule dm = new Monitor();
displayModule dm1=new Projector();
cm.setDisplayModule(dm);
cm.display();
cm.setDisplayModule(dm1);
cm.display();
}
上面的例子中,Computer類聚合了displayModule 接口,而後經過一個方法setDisplayModule來設置具體的接口實現對象,好比顯示器或者投影儀。主程序就相似於裝配器,程序做者就像裝配工人,根據須要裝配不一樣的插件(顯示器或者投影儀對象)。若是Computer類聚合的不是接口而是某個實現類,也就是直接聚合某個插件,這樣就不須要方法setDisplayModule了,可是失去了靈活性,裝配工人也就沒法根據須要裝配不一樣的插件了。
節選自本人做品:《漫談中小企業研發技術棧》第六章。
歡迎關注公衆號: