標籤:訪問 思想 流行 ext ase .com enc .text author
在工廠設計模式中,用戶端可以請求一個對象,而無需知道這個對象來自哪裡;也就是,使用哪個類類產生這個對象。工廠背後的思想是簡化對象的建立。與用戶端自己基於類執行個體化直接建立對象相比,基於一個中心化函數來實現,更易於追蹤建立了哪些對象。通過將建立對象的代碼和使用對象的代碼解耦,工廠能夠降低應用維護的複雜度。
工廠通常有兩種形式:一種是Factory 方法,它是一個方法(或是一個函數),對不同的輸入參數返回不同的對象;第二種是抽象工廠,它是一組建立一系列相關事物對象的Factory 方法。
1. Factory 方法
在Factory 方法模式中,我們執行單個函數,傳入一個參數(提供資訊表明我們想要什麼),但並不要求知道任何關於對象如何?以及對象來自哪裡的細節。
1.1 案例
以下例子將使用Factory 方法來解析兩種流行的人類可讀檔案格式:XML和JSON。我們使用Python髮型版本內建的兩個庫(xml.etree.ElementTree和json)來處理XML和JSON,如下所示:
import xml.etree.ElementTree as etreeimport json
下面是Factory 方法實現(factory_method.py)的完整代碼。
#!/usr/bin/env python# -*- coding: utf-8 -*-# @Date : 2018/7/13 15:34# @Author : Yaheng Wang ([email protected])# @Link : http://www.wy2160640.github.io# @Version : 1.0import xml.etree.ElementTree as etreeimport jsonimport ioclass JSONConnector: def __init__(self, filepath): self.data = {} with io.open(filepath, mode=‘r‘, encoding=‘utf-8‘) as f: self.data = json.load(f) @property def parsed_data(self): return self.dataclass XMLConnector: def __init__(self, filepath): self.tree = etree.parse(filepath) @property def parsed_data(self): return self.treedef connection_factory(filepath): if filepath.endswith(‘json‘): connector = JSONConnector elif filepath.endswith(‘xml‘): connector = XMLConnector else: raise ValueError(‘Cannot connect to {}‘.format(filepath)) return connector(filepath)def connect_to(filepath): factory = None try: factory = connection_factory(filepath) except ValueError as ve: print(ve) return factorydef main(): sqlite_factory = connect_to(‘data/person.sq3‘) print() xml_factory = connect_to(‘data/person.xml‘) xml_data = xml_factory.parsed_data liars = xml_data.findall(".//{}[{}=‘{}‘]".format(‘person‘, ‘lastName‘, ‘Liar‘)) print(‘found: {} persons‘.format(len(liars))) for liar in liars: print(‘first name: {}‘.format(liar.find(‘firstName‘).text)) print(‘last name: {}‘.format(liar.find(‘lastName‘).text)) for p in liar.find(‘phoneNumbers‘): print(‘phone number ({})‘.format(p.attrib[‘type‘]), p.text) print() json_factory = connect_to(‘data/donut.json‘) json_data = json_factory.parsed_data print(‘found : {} donuts‘.format(len(json_data))) for donut in json_data: print(‘name: {}‘.format(donut[‘name‘])) print(‘price: ${}‘.format(donut[‘ppu‘])) for t in donut[‘topping‘]: print(‘topping: {} {}‘.format(t[‘id‘], t[‘type‘]))if __name__ == ‘__main__‘: main()
2. 抽象工廠
抽象工廠設計模式是抽象方法的一種泛化。概括來說,一個抽象工廠是(邏輯上的)一組Factory 方法,其中的每個Factory 方法負責產生不同種類的對象。
2.1案例
抽象工廠有一個優點,在使用Factory 方法時從使用者視角通常是看不到的,那就是抽象工廠能夠通過改變啟用的Factory 方法動態地(運行時)改變使用者行為。一個經典的例子是能夠讓使用者在使用應用時改變應用的觀感,而不需要終止應用然後重新啟動。
想象一下,我們正在創造一個遊戲,或者想在應用中包含一個迷你遊戲讓使用者娛樂娛樂。我們希望至少包含兩個遊戲,一個面向孩子,一個面向成人。在運行時,基於使用者輸入,決定改建立哪個遊戲並運行。遊戲建立部分由一個抽象工廠維護。
抽象工廠實現的完整代碼(abstract_factory.py)如下所示:
#!/usr/bin/env python# -*- coding: utf-8 -*-# @Date : 2018/7/14 15:13# @Author : Yaheng Wang ([email protected])# @Link : http://www.wy2160640.github.io# @Version : 1.0class Frog: def __init__(self, name): self.name = name def __str__(self): return self.name def interact_with(self, obstacle): print(‘{} the Frog encounters {} and {}!‘.format(self, obstacle, obstacle.action()))class Bug: def __str__(self): return ‘a bug‘ def action(self): return ‘eats it‘class FrogWorld: def __init__(self, name): print(self) self.player_name = name def __str__(self): return ‘\n\n\t------ Frog World ------‘ def make_character(self): return Frog(self.player_name) def make_obstacle(self): return Bug()class Wizard: def __init__(self, name): self.name = name def __str__(self): return self.name def interact_with(self, obstacle): print(‘{} the Wizard battles against {} and {}!‘.format(self, obstacle, obstacle.action()))class Ork: def __str__(self): return ‘an evil ork‘ def action(self): return ‘kills it‘class WizardWorld: def __init__(self, name): print(self) self.player_name = name def __str__(self): return ‘\n\n\t------ Wizard World ------‘ def make_character(self): return Wizard(self.player_name) def make_obstacle(self): return Ork()class GameEnvironment: def __init__(self, factory): self.hero = factory.make_character() self.obstacle = factory.make_obstacle() def play(self): self.hero.interact_with(self.obstacle)def validate_age(name): try: age = raw_input(‘Welcome {}. How old are you?\n‘.format(name)) age = int(age) except ValueError as err: print("Age {} is invalid, please try again...".format(age)) return (False, age) return (True, age)def main(): name = raw_input("Hello. What‘s your name?\n") valid_input = False while not valid_input: valid_input, age = validate_age(name) game = FrogWorld if age < 18 else WizardWorld enviroment = GameEnvironment(game(name)) enviroment.play()if __name__ == ‘__main__‘: main()
3.小結
兩種模式都可以用於以下幾種情境:(a)想要追蹤對象的建立時,(b)想要將對象的建立與使用解耦時,(c)想要最佳化應用的效能和資源佔用時。
工廠設計方法模式的實現是一個不屬於任何類的單一函數,負責單一種類對象(一個形狀、一個連接點或者其他對象)的建立。作為樣本,我們實現了一個Factory 方法,提供了訪問XML和JSON檔案的能力。
抽象工廠設計模式的實現是同屬於單個類的許多個Factory 方法用於建立一系列種類的相關對象(一輛車的組件、一個遊戲的環境,或者其他對象)。作為抽象工廠實現的樣本,我們完成了一個迷你遊戲,示範了如何在單個類中使用多個相關工廠。
(轉自精通Python設計模式)Python設計模式之建立型模式——1.原廠模式