詳解設計模式中的Factory 方法模式在Python程式中的運用

來源:互聯網
上載者:User
Factory 方法(Factory Method)模式又稱為虛擬構造器(Virtual Constructor)模式或者多態工廠(Polymorphic Factory)模式,屬於類的建立型模式。在Factory 方法模式中,父類負責定義建立對象的公用介面,而子類則負責產生具體的對象,這樣做的目的是將類的執行個體化操作延遲到子類中完成,即由子類來決定究竟應該實體化哪一個類。
在簡單原廠模式中,一個工廠類處於對產品類進行執行個體化的中心位置上,它知道每一個產品類的細節,並決定何時哪一個產品類應當被執行個體化。簡單原廠模式的優點是能夠使用戶端獨立於產品的建立過程,並且在系統中引入新產品時無需對用戶端進行修改,缺點是當有新產品要加入到系統中時,必須對工廠類進行修改,以加入必要的處理邏輯。簡單原廠模式的致命弱點就是處於核心地位的工廠類,因為一旦它無法確定要對哪個類進行執行個體化時,就無法使用該模式,而Factory 方法模式則可以很好地避免這一問題。
考慮這樣一個應用程式架構(Framework),它可以用來瀏覽各種格式的文檔,如TXT、DOC、PDF、HTML等,設計時為了讓軟體的體繫結構能夠儘可能地通用,定義了Application和Document這兩個抽象父類,客戶必須通過它們的子類來處理某一具體類型的文檔。例如,要想利用該架構來編寫一個PDF檔案瀏覽器,必須先定義PDFApplication和PDFDocument這兩個類,它們應該分別繼承於Application和Document。
Application的職責是對Document進行管理,並且在需要時建立它們,比如當使用者從菜單中選擇Open或者New的時候,Application就要負責建立一個Document的執行個體。顯而易見,被執行個體化的特定Document子類是與具體應用相關的,因此Application無法預測哪個Document的子類將被執行個體化,它只知道一個新的Document何時(When)被建立,但並不知道哪種(Which)具體的Document將被建立。此時若仍堅持使用簡單原廠模式會出現一個非常尷尬的局面:架構必須執行個體化類,但它只知道不能被執行個體化的抽象類別。
解決的辦法是使用Factory 方法模式,它封裝了哪一個Document子類將被建立的資訊,並且能夠將這些資訊從架構中分離出來。1所示,Application的子類重新定義了Application的抽象方法createDocument(),並返回某個恰當的Document子類的執行個體。我們稱createDocument()是一個Factory 方法(factory method),因為它非常形象地描述了類的執行個體化過程,即負責"生產"一個對象。

簡單說來,Factory 方法模式的作用就是可以根據不同的條件產生各種類的執行個體,這些執行個體通常屬於多個相似的類型,並且具有共同的父類。Factory 方法模式將這些執行個體的建立過程封裝了起來,從而簡化了客戶程式的編寫,並改善了軟體體繫結構的可擴充性,使得將來能夠以最小的代價加入新的子類。Factory 方法這一模式適合在如下場合中運用:
當無法得知必須建立的對象屬於哪個類的時候,或者無法得知屬於哪個類的對象將被返回的時候,但前提是這些對象都符合一定的介面標準。
當一個類希望由它的子類來決定所建立的對象的時候,其目的是使程式的可擴充性更好,在加入其他類時更具彈性。
當建立對象的職責被委託給多個協助子類(helper subclass)中的某一個,並且希望將哪個子類是代理者這一資訊局部化的時候。
需要說明的是,使用Factory 方法模式建立對象並不意味著一定會讓代碼變得更短(實事上往往更長),並且可能需要設計更多的輔助類,但它的確可以靈活地、有彈性地建立尚未確定的對象,從而簡化了用戶端應用程式的邏輯結構,並提高了代碼的可讀性和可重用性。

拿一個動物工廠來舉例說明

class Animal(object):  def eat(self, food):    raise NotImplementedError()class Dog(Animal):  def eat(self, food):    print '狗吃', foodclass Cat(Animal):  def eat(self, food):    print '貓吃', foodclass AnimalFactory(object):  def create_animal(self):    raise NotImplementedError()class DogFactory(Animal):  def create_animal(self):    return Dog()class CatFactory(AnimalFactory):  def create_animal(self):    return Cat()def client():  animal_factory = DogFactory()  animal = animal_factory.create_animal()  animal.eat('肉骨頭')  animal_factory = CatFactory()  animal = animal_factory.create_animal()  animal.eat('魚骨頭')

下面是簡單原廠模式的實現:

class Animal(object):  def eat(self, food):    raise NotImplementedError()class Dog(Animal):  def eat(self, food):    print '狗吃', foodclass Cat(Animal):  def eat(self, food):    print '貓吃', fooddef create_animal(name):  if name == 'dog':    return Dog()  elif name == 'cat':    return Cat()def client():  animal = create_animal('dog')  animal.eat('肉骨頭')  animal = create_animal('cat')  animal.eat('魚骨頭')

看起來Factory 方法模式要複雜很多啊,也沒覺得比簡單原廠模式有什麼好處,為什麼還要用Factory 方法模式呢? 簡單原廠模式的優點很明顯,工廠函數封裝了邏輯判斷,用戶端使用負擔要小很多。相應的問題也很明顯,要增加新的產品類型,就需要修改工廠函數,這違背了開閉原則。 但是Factory 方法模式似乎繞了一圈又回到原始時代了,下面寫不就行了嗎,何必外面套一層Factory:

class Animal(object):  def eat(self, food):    raise NotImplementedError()class Dog(Animal):  def eat(self, food):    print '狗吃', foodclass Cat(Animal):  def eat(self, food):    print '貓吃', fooddef client():  dog = Dog()  dog.eat('肉骨頭')  cat = Cat()  cat.eat('魚骨頭')

Factory 方法模式,對於需要做強型別檢查的語言比如Java、C++等在組織代碼時是有好處的。對於Python這種動態語言來說,感覺體現不出太多價值,或許我還沒有理解Factory 方法模式的真諦。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.