一、設計模式
設計模式:對軟件設計中普遍存在(反復出現)的各種問題,所提出的解決方案。
每一個設計模式系統地命名、解釋和評價了面向對象系統中一個重要的和重復出現的設計。
設計模式的創始人,一般稱為“四人幫”(Gang of Four, GoF):Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides......他們編寫一套書來介紹23種設計模式:《設計模式:可復用面向對象軟件的基礎》。
二、面向對象回顧
設計模式是用來設計面向對象系統中的設計。不解決面向過程的問題。
1、面向對象的三大特性
封裝:把數據和函數封裝到一個類里,體現類內和類外。
繼承:由於有了封裝,需要通過繼承在類之間復用代碼。
多態:python本身是一門多態語言,因此不需去處理多態的問題。Java中則會區分虛類和普通類。
因此這三個特性是一個遞進的關系。
2、接口
接口:若干抽象方法的集合。
作用:限制實現接口類必須按照接口給定的調用方式實現這些方法;對高層模塊隱藏了類的內部實現。
# 方法一:繼承 # 存在的問題是:如果不調用pay方法並不會報錯 class Payment: def pay(self, money): raise NotImplementedError class Alipay(Payment): pass class WechatPay(Payment): pass p = Alipay() p.pay(100) # 方法二:抽象類 # 約束子類必須實現抽象類:TypeError: Can't instantiate abstract class Alipay with abstract methods pay from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): # abstract class @abstractmethod def pay(self, money): # 抽象方法 pass class Alipay(Payment): def pay(self, money): # 實現Payment接口 print('支付寶支付%d元' % money) class WechatPay(Payment): def pay(self, money): # 實現Payment接口 print("微信支付%d元" % money) p = Alipay() p.pay(100)
不用去查看具體實現,只要去查看接口(抽象類)的結構和注釋,就可以了解需要傳遞的參數和pay方法的使用。
在寫底層模塊或者開源框架時需要大量應用設計模式,優化封裝,讓程序員在學習和使用時非常方便。
三、面向對象設計SOLID原則
不管是面向對象設計還是各個設計模式都需要遵循這五大原則。
- 開放封閉原則:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。即軟件實體應盡量在不修改原有代碼的情況下進行擴展。
- 里氏替換原則:所有引用父類的地方必須能透明地使用其子類的對象。(子類是特殊的父類,子類繼承父類時同樣方法的表現一致)
# 子類和父類的show_name內部實現和邏輯可能不同,但是參數和返回值是相同的 class User: def show_name(self): pass class VIPUser(User): def show_name(self): pass def show_user(u): # u可以是普通用戶或VIP res = u.show_name()
- 依賴倒置原則:高層模塊不應該依賴低層模塊,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。換言之,要針對接口編程,而不是針對實現編程。
from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): # 抽象 # abstract class @abstractmethod def pay(self, money): # 抽象方法 pass class Alipay(Payment): # 細節 def pay(self, money): # 實現Payment接口 print('支付寶支付%d元' % money) class WechatPay(Payment): # 細節 def pay(self, money): # 實現Payment接口 print("微信支付%d元" % money)
- 接口隔離原則:使用多個專門的接口,而不使用單一的總接口,即客戶端不應該依賴那些它不需要的接口。
from abc import ABCMeta, abstractmethod # (一)單一總接口的情況 # 子類必須實現所有抽象方法,但其實很多方法是子類不需要的 class Animal(metaclass=ABCMeta): @abstractmethod def walk(self): pass @abstractmethod def swim(self): pass @abstractmethod def fly(self): pass class Tiger(Animal): # Class Tiger must implement all abstract methods def walk(self): print("老虎走路") # (二)多個接口隔離情況 class LandAnimal(metaclass=ABCMeta): @abstractmethod def walk(self): pass class WaterAnimal(metaclass=ABCMeta): @abstractmethod def swim(self): pass class SkyAnimal(metaclass=ABCMeta): @abstractmethod def fly(self): pass class Tiger(LandAnimal): def walk(self): print("老虎走路") class Frag(LandAnimal,WaterAnimal): # 青蛙多繼承 pass
- 單一職責原則:不要存在多於一個導致類變更的原因。通俗的說,即一個類只負責一項職責。
四、設計模式分類
1、創建型模式(5種)
主要聚焦怎么去創建對象。目的是為了隱藏底層模塊的邏輯。
工廠方法模式、抽象工廠模式、創建者模式、原型模式、單例模式。
2、結構型模式(7種)
主要關注在幾個類之間怎么組合協同工作在一起。
適配器模式、橋模式、組合模式、裝飾模式、外觀模式、享元模式、代理模式。
3、行為型模式(11種)
主要關注方法和行為的完成。
解釋器模式、責任鏈模式、命令模式、迭代器模式、中介者模式、備忘錄模式、觀察者模式、狀態模式、策略模式、訪問者模式、模板方法模式。
五、設計模式總結
python這門語言是一個動態語言,對參數、父類子類等限制不嚴格。對設計模式並不強求,不是完全契合,而java則是完全與設計模式契合。但是了解一些設計模式對寫出優秀代碼還是非常有幫助的。
在寫大型項目時,尤其是底層代碼、開源框架等時,設計模式的優勢將更加突出。