建立型模式---工廠模式

工廠模式html

在工廠設計模式中,客戶端能夠請求一個對象,而無須要知道這個對象來自哪裏,也就是使用哪一個類來生成這個對象。工廠背後的思想是簡化對象的建立。與客戶端本身基於類實例化直接建立對象相比,基於一箇中心化函數來實現,更易於追蹤建立了那些對象。
工廠一般有兩種形式:一種是工廠方法,它是一個方法(函數),對不一樣的輸入參數返回不一樣的對象;第二種是抽象工廠,它是一組用於建立一系列相關事物對象的工廠方法。

工廠方法sql

在工廠方法模式中,咱們執行單個函數,傳入一個參數(提供信息代表咱們想要什麼),但不要求直到任何關於對象如何實現以及對象來自哪裏的細節。
現實生活中的例子:塑料玩具製造製造塑料玩具的壓塑粉都是同樣的,可是使用不一樣塑料模具就能產出不一樣的外形。好比有一個工廠方法,輸入是目標外形的名稱,輸出則是要求的塑料外形。
軟件中的例子:Django框架使用工廠方法模式來建立表單字段。Django的forms模塊支持不一樣種類字段(CharField,EmailField)的建立和制定(max_length,required)。
應用案例:
若是由於應用建立對象的代碼分佈在多個不一樣的地方,而不是僅在一個函數/方法中,你發現無法跟蹤這些對象,那麼應該考慮使用工廠方法模式。工廠方法集中地在一個地方建立對象,使對象跟蹤變得更容易。

案例實現django

如下例子將關注兩種流行的人類可讀文件格式:XML和JSON。
在當前這個問題中,咱們有一些輸入數據存儲在一個XML文件和JSON文件中,要對這兩個文件進行解析,獲取一些信息。同時,但願對這些(以及未來涉及的的全部)外部服務進行集中式的客戶端鏈接。咱們使用工廠方法來解決這個問題。
#數據來源:
json文件:http://opensource.adobe.com/Spry/samples/data_region/JSONDataSetSample.html#Example4
xml文件:https://en.wikipedia.org/wiki/JSON#XML
import xml.etree.ElementTree as etree
import json

#類JSONConnector解析JSON文件,經過parsed_data()方法以一個字典dict的形式返回數據
class JSONConnector:
    def __init__(self,filepath):
        self.data = {}
        with open(filepath,mode='r',encoding='utf-8') as f:
            self.data = json.load(f)

    @property
    def parsed_data(self):
        return self.data

#類XMLConnector解析XML文件,經過parsed_data()方法以xml.etree.Element列表的形式返回全部數據。
class XMLConnector:
    def __init__(self,filepath):
        self.tree = etree.parse(filepath)

    @property
    def parsed_data(self):
        return self.tree

#工廠方法connect_factory,基於輸入路徑的擴展名返回一個JSONConnector或XMLConnector的實例
def connect_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)

#函數connnect_to對工廠方法進行包裝,添加了異常處理
def connect_to(filepath):
    factory = None
    try:
        factory = connect_factory(filepath)
    except ValueError as e:
        print(e)
    return factory

def main():
    sqlite_factory = connect_to('person.sq3')
    print()

    xml_factory = connect_to('test2.xml')
    xml_data = xml_factory.parsed_data
    liars = xml_data.findall(".//{}[{}='{}']".format('person','lastName','Liar'))
    for liar in liars:
        print('first name:{}'.format(liar.find('firstName').text))
        print('last name:{}'.format(liar.find('lastName').text))
        [print('phone number ({}):'.format(p.text)) for p in liar.find('phoneNumber')]#待完善XML模式匹配語法
    print()

    json_factory = connect_to('test1.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']))
        [print('topping:{}{}'.format(t['id'],t['type'])) for t in donut['topping']]

if __name__ == '__main__':
    main()

抽象工廠json

抽象工廠設計模式是抽象方法的一種泛化。歸納來講,一個抽象工廠是(邏輯上的)一組工廠方法,其中每一個工廠方法負責產生不一樣種類的對象。
現實生活中的例子:汽車製造業應用了抽象工廠的思想。衝壓不一樣汽車模型的部件(車門、儀表盤、車篷以及擋泥板的等)所使用的的機件是相同的。機件組裝起來的模型隨時可配置,且易於改變。
軟件中的例子:程序包django_factory是一個用於在測試中建立Django模型的抽象工廠實現,可用來爲支持測試專有屬性的模型建立實例。這能讓測試代碼的可讀性更高,且能避免共享沒必要要的代碼,故有其存在的價值。
應用案例:
抽象工廠模式是工廠方法模式的一種泛化,因此它能提供相同的好處:讓對象的建立更容易追蹤;將對象建立與使用解耦;提供優化內存佔用和應用性能的潛力。
那咱們什麼時候使用工廠方法,什麼時候又該使用抽象工廠?答案是,一般一開始使用工廠方法,由於它更簡單。若是後來發現應用須要許多工廠方法,那麼會將建立一些列對象的過程合併在一塊兒更合理,從而最終引入抽象工廠。
#想象一下,咱們正在創造一個遊戲,或者想在應用中包含一個迷你遊戲讓用戶娛樂一下。咱們但願至少包含兩個遊戲,一個面向孩子,一個面向大人。在運行時,基於用戶輸入,決定該建立那個遊戲並運行。遊戲的建立部分由一個抽象工廠維護。
class 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'

#抽象工廠FrogWorld,其主要職責是建立遊戲的主人公和障礙物。
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 'a evil ork'

    def action(self):
        return 'kills it'

#抽象工廠WizardWorld,相似於FrogWorld
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()

#類GameEnvironment是咱們遊戲的主入口,它接受factory做爲輸入,用其建立遊戲的世界。
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)

#validate_age提示用戶輸入一個有效的年齡
def validate_age(name):
    try:
        age = input('Welcome {}.How old are you?'.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 = input("Hello,What's your name?")
    valid_input = False
    while not valid_input:
        valid_input,age = validate_age(name)
        game = FrogWorld if age<18 else WizardWorld
    environment = GameEnvironment(game(name))
    environment.play()

if __name__ == '__main__':
    main()

小結設計模式

工廠方法設計模式的實現是一個不屬於任何類的單一函數,負責單一種類對象的建立。
抽象工廠設計模式的實現是同屬於單個類的許多個工廠方法用於建立一系列種類的相關對象。
相關文章
相關標籤/搜索