python設計模式之模版方法設計模式

  我們在使用python的flask框架時,可能會經常用到生命周期函數如:before_request, before_first_request,或者訊號等,剛開始學的時候就想只要寫一個函數,然後加上一個裝飾器居然就可以實現這種開掛般的效果,那時感覺這框架程式碼寫得真棒, 再過些時間自己學會閱讀框架源碼時,在flask源碼中的wsgi_app函數裡面發現了奧秘,原來是這樣寫就能實現插入生命周期的效果啊,時間在走知識在漲,不知不覺走進了設計模式的天堂,再猛然看flask框架源碼的時候就覺得,原來如此,這不就是模版方法設計模式的具體應用嗎?接下來我們來看看什麼是模版方法設計模式來揭開它的神秘面紗。

  模版方法設計模式GOF官方的解釋是: 定義一個操作中的演算法的骨架(穩定), 而將一些步驟(變化)延遲到子類中。 使得子類可以不改變(復用)一個演算法的結構即可重定義該演算法的某些特定步驟。

 

  模版方法設計模式的框架圖如下:

  可以看到在抽象類中定義了一系列固定流程的方法, 而在子類中去重寫或者實現具體的某些步驟。

  接下來我們用丐版的Flask來演示模版方法設計模式的精髓,聲明flask框架並不是這樣實現的,只是含有模版設計模式的思想, 我們的演示只是把這思想展示出來。

 

01、沒有用設計模式Flask

 

class Flask:

    def before_request(self):
        pass

    def request(self):
        pass

    def context(self):
        print("我在存儲上下文")

    def response(self):
        pass

    def clear(self):
        print("我在清除上下文")


class Application(Flask):

    def before_request(self):
        print("我在煮飯前加了一個蛋")

    def request(self):
        print("我正在吃飯")

    def response(self):
        print("終於吃好了")

    def run(self):
        self.before_request()
        self.request()
        self.context()
        self.request()
        self.clear()

Application().run()

 

   我們發現,run方法執行的步驟是固定的,這樣每個app繼承Flask的時候都要實現一個run方法,加重了app開發者的負擔,因為run主程式的步驟是固定的,我們把run方法的實現移到抽象類Flask中,看一下效果。

 

02、 用了模版設計模式的Flask

 

class Flask:

    def before_request(self):
        pass

    def request(self):
        pass

    def context(self):
        print("我在存儲上下文")

    def response(self):
        pass

    def clear(self):
        print("我在清除上下文")

    def run(self):
        self.before_request()
        self.request()
        self.context()
        self.request()
        self.clear()


class Application(Flask):

    def before_request(self):
        print("我在煮飯前加了一個蛋")

    def request(self):
        print("我正在吃飯")

    def response(self):
        print("終於吃好了")

Application().run()

 

 

  這裡我們就是把主程式run方法移動到抽象類Flask中,這時作為我們開發者,我們只要實現具體的步驟如,before_request和request等就可以了,這樣大大減輕了開發者負擔。

 

03、什麼時候使用模版方法設計模式

  在構建過程中,對於某一項任務,它通常有穩定的整體操作結構, 但各個子步驟卻有很多改變的需求,或者由於固有的原因(比如框架與應用之間的關係)而無法和任務的整體結構同時實現。在這個時候模版方法設計模式將會是你很好的一個選擇。

 

04、總結

  模版方法設計模式是一種非常基礎性的設計模式, 在面向對象系統中有大量的應用。它用最簡潔的機制(多態)為很多應用程式框架提供了靈活的擴展點,是程式碼復用方面的基本實現結構。

除了可以靈活應對子步驟的變化外, 「不要調用我, 讓我來調用你」的反向控制結構是模版方法設計模式的典型應用。

 

最後還是奉上設計模式的8大基本設計原則:

  1. 依賴倒置原則(DIP)
  • 高層模組(穩定)不應該依賴於低層模組(變化),二者都應該依賴於抽象(穩定) 。
  • 抽象(穩定)不應該依賴於實現細節(變化) ,實現細節應該依賴於抽象(穩定)。
  1. 開放封閉原則(OCP)
  • 對擴展開放,對更改封閉。
  • 類模組應該是可擴展的,但是不可修改。
  1. 單一職責原則(SRP)
  • 一個類應該僅有一個引起它變化的原因。
  • 變化的方向隱含著類的責任。
  1. Liskov 替換原則(LSP)
  • 子類必須能夠替換它們的基類(IS-A)。
  • 繼承表達類型抽象。
  1. 介面隔離原則(ISP)
  • 不應該強迫客戶程式依賴它們不用的方法。
  • 介面應該小而完備。
  1. 優先使用對象組合,而不是類繼承
  • 類繼承通常為「白箱復用」,對象組合通常為「黑箱復用」 。
  • 繼承在某種程度上破壞了封裝性,子類父類耦合度高。
  • 而對象組合則只要求被組合的對象具有良好定義的介面,耦合度低。
  1. 封裝變化點
  • 使用封裝來創建對象之間的分界層,讓設計者可以在分界層的一側進行修改,而不會對另一側產生不良的影響,從而實現層次間的松耦合。
  1. 針對介面編程,而不是針對實現編程
  • 不將變數類型聲明為某個特定的具體類,而是聲明為某個介面。
  • 客戶程式無需獲知對象的具體類型,只需要知道對象所具有的介面。
  • 減少系統中各部分的依賴關係,從而實現「高內聚、松耦合」的類型設計方案