二十三種設計模式
一、創建型:
單例模式、工廠模式、抽象工廠模式、原型模式、建造者模式;
二、結構型:
代理模式,裝飾器模式、適配器模式、外觀模式、組合模式、享元模式、橋梁模式;
三、行為型:
策略模式、責任鏈模式、命令模式、中介者模式、模板方法模式、迭代器模式、訪問者模式、觀察者模式、解釋器模式、備忘錄模式、狀態模式。
三類設計模式的特點:
六大原則
一、開放封閉(簡稱開閉)原則
Open-Close Principle(OCP):一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。目的就是保證程序的擴展性好,易於維護和升級。
開閉原則被稱為面向對象設計的基石,實際上,其他原則都可以看作是實現開閉原則的工具和手段。意思就是:軟件對擴展應該是開放的,對修改是封閉的,通俗來說就是,開發一個軟件時,應該對其進行功能擴展,而在進行這些擴展時,不需要對原來的程序進行修改。
好處是:軟件可用性非常靈活,擴展性強。需要新的功能時,可以增加新的模塊來滿足新需求。另外由於原來的模塊沒有修改,所以不用擔心穩定性的問題。
二、單一職責原則
Single-Responsibilitiy Principle(SRP):對一個類而言,應該僅有一個引起它變化的原因。如果存在多於一個動機去改變一個類,那么這個類就具有多於一個的職責,就應該把多余的職責分離出去,再去創建一些類來完成每一個職責。
舉個例子:一個人身兼數職,而這些事情相關性不大,甚至有沖突,那他就無法很好的解決這些問題職責,應該分到不同的人身上去做。
單一職責原則是實現高內聚低耦合的最好方法,沒有之一。
1 class CellPhone: 2 3 def call(string person): 4 //打電話 5 pass 6 def hangup(): 7 //掛斷電話 8 pass 9 10 def sendMessage(string person): 11 //發送信息 12 pass 13 def receiveMessage(): 14 //接受信息 15 pass
上面的手機類雖然符合人們對手機的認識,但是實際上卻擁有兩個不同的職責:打電話、掛斷電話和發短信、接受信息,因此引起它變化的原因就有多個,是比較脆弱的設計,應該將兩種行為分離。
三、里氏代換原則
Liskov Substitution Principle:子類可以擴展父類的功能,但是不能改變父類原有的功能。
在第一條原則開放封閉原則中,主張“抽象”和“多態”。維持設計的封裝性“抽象”是語言提供的功能,“多態”由繼承語意實現。因此如何去度量繼承關系中的質量?
答案是:繼承必須明確確保超類(父類)所擁有的性質在子類中仍然成立。
在面向對象的思想中,一個對象就是一組狀態和一系列行為的組合體。狀態是對象的內在特性,行為是對象的外在特性。LSP表述的就是在同一繼承體系中的隊形應該具有共同的行為特征。
1 class bird: 2 color = '' 3 weight = '' 4 def eat(): 5 pass 6 def fly(): 7 print("fly") 8 9 class chicken(bird): 10 def fly(): 11 print("can not fly")
在上述例子中,父類也就是對象鳥有兩個行為也就是方法:eat()和fly(),在子類chicken中這兩個行為也應該成立,但是現實中chicken是不能飛的,因此chicken中的fly()方法覆蓋了父類中的方法。違反了VSP。
四、依賴倒置原則
Dependence Inversion Principle(DIP):是一個類與類之間的調用規則。這里的依賴就是代碼中的耦合。高層模塊不應該依賴底層模塊,二者都應該依賴其抽象了;抽象不依賴細節;細節應該依賴抽象。接口編程。
主要思想就是:如果一個類中的一個成員或者參數成為一個具體的類型,那么這個類就依賴這個具體類型。如果在一個繼承結構中,上層類中的一個成員或者參數為一個下層類型,那么就是這個繼承結構高層依賴底層,就要盡量面向抽象或者接口編程。
舉例:存在一個Driver類,成員為一個Car對象,還有一個driver()方法,Car對象中有兩個方法start()與stop()。顯然Driver依賴Car,也就是說Driver類調用了Car類中的方法。但是當增加Driver類對於Bus類的支持時(司機有需要開公交車),就必須更改Driver中的代碼,就破壞了開放封閉原則。根本原因在於高層的的Driver類與底層的Car類僅僅的耦合在一起的。解決方法之一就是:對Car類和Bus類進行抽象,引入抽象類Automoble。而Car和Bus則是對Automobile的泛化。
經過這樣的改造發現,原本的高層依賴底層,變成了高層與底層同時依賴抽象。這就是依賴倒轉原則的本質。
五、接口隔離原則
接口隔離原則(Interface Segregation Principle):用於恰當的划分角色和接口,具有兩種含義:1、用戶不應該依賴它不需要的借口;2、類間的依賴關系應該建立在最小的的接口上。
將這兩個定義概括為一句話:建立單一接口,代替龐大臃腫的接口。通俗來說就是:接口盡量細化,同時保證接口中的方法盡量的少。一個接口中包含太多的行為時,會導致它們與客戶端的不正常依賴關系,要做的就是分離接口,從而實現解耦。
回到上述的單一職責原則,要求行為分離接口接口細化,感覺有些相同。但實際上,單一職責原則要求類與接口的職責單一,注重的是職責,沒有要求接口盡量的少。
在接口隔離原則中,要求盡量使用多個專門的接口。專門的接口也就是提供給多個模塊的接口。提供給幾個模塊就應該有幾個接口,而不是建立一個臃腫龐大的接口,所有的模塊都可以訪問。
但是接口的設計是有限度的。接口的設計粒度越小系統越靈活,這是事實,但是接口太多這也就使得結構復雜,維護難度大。因此實際中,怎樣把握就靠開發的經驗和常識了。
六、迪米特原則
Law of Demeter(最小知識原則):一個對象應該對其他對象有最少的了解。通俗來說就是,一個類對自己需要耦合或者調用的類知道的最少,你類內部怎么復雜,我不管,那是你的事,我只知道你有那么多公用的方法,我能調用。
迪米特原則不希望類與類之間建立直接的接觸。如果真的需要有聯系,那么就通過它們的友元類來傳達。舉例來說:你需要買房子了,現在存在三座合適的樓盤A,B,C,但是你不必直接去樓盤買樓,而是在售樓處去了解情況。這樣就減少了你(購房者)與樓盤兩個類之間耦合。
但是應用迪米特原則很可能會造成一個后果:系統會存在大量的中介類,這些類(如上面的售樓處類)之所以存在是為了傳遞類之間的相互調用關系,這就一定會程度上增加了系統的復雜度。
迪米特原則核心觀念就是:類間解耦,弱耦合。
源碼地址:https://github.com/weilanhanf/PythonDesignPatterns