真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Python中工廠方法模式有什么用

這篇文章主要為大家展示了“Python中工廠方法模式有什么用”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Python中工廠方法模式有什么用”這篇文章吧。

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價值的長期合作伙伴,公司提供的服務(wù)項目有:主機(jī)域名、網(wǎng)頁空間、營銷軟件、網(wǎng)站建設(shè)、海拉爾網(wǎng)站維護(hù)、網(wǎng)站推廣。

工廠方法(Factory Method)模式又稱為虛擬構(gòu)造器(Virtual Constructor)模式或者多態(tài)工廠(Polymorphic Factory)模式,屬于類的創(chuàng)建型模式。在工廠方法模式中,父類負(fù)責(zé)定義創(chuàng)建對象的公共接口,而子類則負(fù)責(zé)生成具體的對象,這樣做的目的是將類的實例化操作延遲到子類中完成,即由子類來決定究竟應(yīng)該實體化哪一個類。

在簡單工廠模式中,一個工廠類處于對產(chǎn)品類進(jìn)行實例化的中心位置上,它知道每一個產(chǎn)品類的細(xì)節(jié),并決定何時哪一個產(chǎn)品類應(yīng)當(dāng)被實例化。簡單工廠模式的優(yōu)點是能夠使客戶端獨立于產(chǎn)品的創(chuàng)建過程,并且在系統(tǒng)中引入新產(chǎn)品時無需對客戶端進(jìn)行修改,缺點是當(dāng)有新產(chǎn)品要加入到系統(tǒng)中時,必須對工廠類進(jìn)行修改,以加入必要的處理邏輯。簡單工廠模式的致命弱點就是處于核心地位的工廠類,因為一旦它無法確定要對哪個類進(jìn)行實例化時,就無法使用該模式,而工廠方法模式則可以很好地避免這一問題。

考慮這樣一個應(yīng)用程序框架(Framework),它可以用來瀏覽各種格式的文檔,如TXT、DOC、PDF、HTML等,設(shè)計時為了讓軟件的體系結(jié)構(gòu)能夠盡可能地通用,定義了Application和Document這兩個抽象父類,客戶必須通過它們的子類來處理某一具體類型的文檔。例如,要想利用該框架來編寫一個PDF文件瀏覽器,必須先定義PDFApplication和PDFDocument這兩個類,它們應(yīng)該分別繼承于Application和Document。

Application的職責(zé)是對Document進(jìn)行管理,并且在需要時創(chuàng)建它們,比如當(dāng)用戶從菜單中選擇Open或者New的時候,Application就要負(fù)責(zé)創(chuàng)建一個Document的實例。顯而易見,被實例化的特定Document子類是與具體應(yīng)用相關(guān)的,因此Application無法預(yù)測哪個Document的子類將被實例化,它只知道一個新的Document何時(When)被創(chuàng)建,但并不知道哪種(Which)具體的Document將被創(chuàng)建。此時若仍堅持使用簡單工廠模式會出現(xiàn)一個非常尷尬的局面:框架必須實例化類,但它只知道不能被實例化的抽象類。

解決的辦法是使用工廠方法模式,它封裝了哪一個Document子類將被創(chuàng)建的信息,并且能夠?qū)⑦@些信息從框架中分離出來。如圖1所示,Application的子類重新定義了Application的抽象方法createDocument(),并返回某個恰當(dāng)?shù)腄ocument子類的實例。我們稱createDocument()是一個工廠方法(factory method),因為它非常形象地描述了類的實例化過程,即負(fù)責(zé)"生產(chǎn)"一個對象。

Python中工廠方法模式有什么用

簡單說來,工廠方法模式的作用就是可以根據(jù)不同的條件生成各種類的實例,這些實例通常屬于多個相似的類型,并且具有共同的父類。工廠方法模式將這些實例的創(chuàng)建過程封裝了起來,從而簡化了客戶程序的編寫,并改善了軟件體系結(jié)構(gòu)的可擴(kuò)展性,使得將來能夠以最小的代價加入新的子類。工廠方法這一模式適合在如下場合中運(yùn)用:

◆當(dāng)無法得知必須創(chuàng)建的對象屬于哪個類的時候,或者無法得知屬于哪個類的對象將被返回的時候,但前提是這些對象都符合一定的接口標(biāo)準(zhǔn)。

◆當(dāng)一個類希望由它的子類來決定所創(chuàng)建的對象的時候,其目的是使程序的可擴(kuò)展性更好,在加入其他類時更具彈性。

◆當(dāng)創(chuàng)建對象的職責(zé)被委托給多個幫助子類(helper subclass)中的某一個,并且希望將哪個子類是代理者這一信息局部化的時候。

需要說明的是,使用工廠方法模式創(chuàng)建對象并不意味著一定會讓代碼變得更短(實事上往往更長),并且可能需要設(shè)計更多的輔助類,但它的確可以靈活地、有彈性地創(chuàng)建尚未確定的對象,從而簡化了客戶端應(yīng)用程序的邏輯結(jié)構(gòu),并提高了代碼的可讀性和可重用性。

二、模式引入

工廠方法這一模式本身雖然并不復(fù)雜,但卻是最重要的設(shè)計模式之一,無論是在COM、CORBA或是EJB中,都可以隨處見到它的身影。面向?qū)ο蟮囊粋€基本思想是在不同的對象間進(jìn)行責(zé)權(quán)的合理分配,從本質(zhì)上講,工廠方法模式是一種用來創(chuàng)建對象的多態(tài)方法(polymorphic method),它在抽象父類中聲明用來創(chuàng)建對象的方法接口,而具體子類則通過覆蓋該方法將對象的創(chuàng)建過程局部化,包括是否實例化一個子類,以及是否對它進(jìn)行初始化等等。從某種程度上說,工廠方法可以看成是構(gòu)造函數(shù)的特殊化,其特殊性表現(xiàn)在能夠用一致的方法來創(chuàng)建不同的對象,而不用擔(dān)心當(dāng)前正在對哪個類進(jìn)行實例化,因為究竟創(chuàng)建哪個類的對象將取決于它的子類。

假設(shè)我們打算開發(fā)一個用于個人信息管理(Personal Information Manager,PIM)的軟件,它可以保存日常工作和生活中所需的各種信息,包括地址本、電話簿、約會提醒、日程安排等等。很顯然,PIM用戶界面(User Interface)的設(shè)計將是比較復(fù)雜的,因為必須為每種信息的輸入、驗證和修改都提供單獨的界面,以便同用戶進(jìn)行交互。比較簡單的做法是在PIM中為各種信息的處理編寫相應(yīng)的用戶界面,但代價是將導(dǎo)致軟件的可擴(kuò)展性非常差,因為一旦今后要加入對其他信息(比如銀行帳戶)進(jìn)行管理的功能時,就必須對PIM進(jìn)行修改,添加相應(yīng)的用戶界面,從而最終導(dǎo)致PIM變得越來越復(fù)雜,結(jié)構(gòu)龐大而難以維護(hù)。改進(jìn)的辦法是將處理各種信息的用戶界面從PIM中分離出來,使PIM不再關(guān)心用戶如何輸入數(shù)據(jù),如何對用戶輸入進(jìn)行驗證,以及用戶如何修改信息等,所有的這些都交由一個專門的軟件模塊來完成,而PIM要做的只是提供一個對這些個人信息進(jìn)行管理的總體框架。

在具體實現(xiàn)時可以設(shè)計一個通用接口Editable,并且讓所有處理特定個人信息(如通信地址和電話號碼)的用戶界面都繼承于它,而PIM則通過Editable提供的方法getEditor()獲得Editor的一個實例,并利用它來對用戶輸入進(jìn)行統(tǒng)一的處理。例如,當(dāng)用戶完成輸入之后,PIM可以調(diào)用Editor中的方法getContent()來獲取用戶輸入的數(shù)據(jù),或者調(diào)用resetUI()來清除用戶輸入的數(shù)據(jù)。在采用這一體系結(jié)構(gòu)之后,如果要擴(kuò)展PIM的功能,只需添加與之對應(yīng)的Editable和Editor就可以了,而不用對PIM本身進(jìn)行修改。

現(xiàn)在離目標(biāo)還有一步之遙,由于Editable和Editor都只是通用的接口,但PIM卻需要對它們的子類進(jìn)行實例化,此時自然應(yīng)該想到運(yùn)用工廠方法模式,為PIM定義一個EditableFactory接口來創(chuàng)建Editable的對象。這樣一來,整個PIM的體系結(jié)構(gòu)就將如圖2所示。

Python中工廠方法模式有什么用

Editable接口定義了一個公共的構(gòu)造性方法(builder method)getEditor(),它返回一個Editor對象,其完整的代碼如清單1所示。任何一項個人信息都擁有自己獨立的用戶界面(Editor),負(fù)責(zé)獲取數(shù)據(jù)并在需要的時候進(jìn)行修改,而PIM唯一要做事情的只是通過Editable來獲得Editor,并利用它來對用戶輸入的數(shù)據(jù)進(jìn)行相應(yīng)的操作。

代碼清單1:editable.py  class Editable:    """ 個人信息用戶界面的公共接口 """    # 獲得個人信息編輯界面    def getEditor(self):  pass

Editor接口給出了處理所有個人信息的公共接口,其完整的代碼如清單2所示。PIM通過調(diào)用getUI()方法能夠獲得與用戶進(jìn)行交互的UI組件,根據(jù)當(dāng)前正在處理的個人信息的不同,這些組件可能簡單到只是一個文本輸入框,也可以復(fù)雜到是一個包含了多個圖形控件(Widget)的對話框。利用Editor提供的getContent()、commitChanges()和resetUI()方法,PIM還可以獲取、提交或者清空用戶輸入的個人信息。在引入Editor之后, PIM就能夠從處理特定個人信息的用戶界面中解脫出來,從而可以將注意力集中在如何對這些信息進(jìn)行統(tǒng)一管理的問題上。

代碼清單2:editor.py  class Editor:    """ 用戶使用特定的Editor來編輯個人信息 """    # 獲取代表用戶界面(UI)的對象    def getUI(self):      pass        # 獲取用戶輸入的數(shù)據(jù)    def getContent(self):      pass    # 提交用戶輸入的數(shù)據(jù)    def commitChanges(self):      pass          # 清空用戶輸入的數(shù)據(jù)    def resetUI(self):      pass

EditableAddress是Editable的一個具體實現(xiàn),PIM使用它來處理個人地址信息,其完整的代碼如清單3所示。

代碼清單3:editableaddress.py  from editor import Editor  from editable import Editable  import Tkinter  class EditableAddress(Editable):    """ 用于處理個人地址信息的Editable """        # 構(gòu)造函數(shù)    def __init__(self, master):      self.master = master      self.name = ""     self.province = ""     self.city = ""     self.street = ""     self.zipcode = ""     self.editor = AddressEditor(self)          # 獲取相關(guān)聯(lián)的Editor    def getEditor(self):      return self.editor          class AddressEditor(Editor, Tkinter.Frame):    """ 用于處理個人地址信息的Editor """        # 構(gòu)造函數(shù)    def __init__(self, owner):      Tkinter.Frame.__init__(self, owner.master)      self.owner = owner      self.name = Tkinter.StringVar()      self.province = Tkinter.StringVar()      self.city = Tkinter.StringVar()      self.street = Tkinter.StringVar()      self.zipcode = Tkinter.StringVar()      self.createWidgets()         # 構(gòu)造用戶界面    def createWidgets(self):      # 姓名      nameFrame = Tkinter.Frame(self)      nameLabel = Tkinter.Label(nameFrame, text="Name:")      nameEntry = Tkinter.Entry(nameFrame, textvariable=self.name)      nameLabel.config(anchor=Tkinter.E, width=8, pady=3)      nameLabel.pack(side=Tkinter.LEFT)      nameEntry.pack(side=Tkinter.LEFT)      nameFrame.pack()            # 省份      provinceFrame = Tkinter.Frame(self)      provinceLabel = Tkinter.Label(provinceFrame, text="Province:")      provinceEntry = Tkinter.Entry(provinceFrame, textvariable=self.province)      provinceLabel.config(anchor=Tkinter.E, width=8, pady=3)      provinceLabel.pack(side=Tkinter.LEFT)      provinceEntry.pack(side=Tkinter.LEFT)      provinceFrame.pack()      # 城市      cityFrame = Tkinter.Frame(self)      cityLabel = Tkinter.Label(cityFrame, text="City:")      cityEntry = Tkinter.Entry(cityFrame, textvariable=self.city)      cityLabel.config(anchor=Tkinter.E, width=8, pady=3)      cityLabel.pack(side=Tkinter.LEFT)      cityEntry.pack(side=Tkinter.LEFT)      cityFrame.pack()            # 街道      streetFrame = Tkinter.Frame(self)      streetLabel = Tkinter.Label(streetFrame, text="Street:")      streetEntry = Tkinter.Entry(streetFrame, textvariable=self.street)      streetLabel.config(anchor=Tkinter.E, width=8, pady=3)      streetLabel.pack(side=Tkinter.LEFT)      streetEntry.pack(side=Tkinter.LEFT)      streetFrame.pack()            # 郵編      zipcodeFrame = Tkinter.Frame(self)      zipcodeLabel = Tkinter.Label(zipcodeFrame, text="ZIP Code:")      zipcodeEntry = Tkinter.Entry(zipcodeFrame, textvariable=self.zipcode)      zipcodeLabel.config(anchor=Tkinter.E, width=8, pady=3)      zipcodeLabel.pack(side=Tkinter.LEFT)      zipcodeEntry.pack(side=Tkinter.LEFT)      zipcodeFrame.pack()          # 重載Editor中的方法,獲取代表用戶界面(UI)的對象    def getUI(self):      return self        # 重載Editor中的方法,獲取用戶輸入的數(shù)據(jù)    def getContent(self):      content  = "    Name: " + self.name.get() + "\n"      content += "Province: " + self.province.get() + "\n"       content += "    City: " + self.city.get() + "\n"       content += "  Street: " + self.street.get() + "\n"       content += "ZIP Code: " + self.zipcode.get()      return content        # 重載Editor中的方法,提交用戶輸入的數(shù)據(jù)    def commitChanges(self):      selfself.owner.name = self.name.get()      selfself.owner.province = self.province.get()      selfself.owner.city = self.city.get()      selfself.owner.street = self.street.get()      selfself.owner.zipcode = self.zipcode.get()    # 重載Editor中的方法,清空用戶輸入的數(shù)據(jù)    def resetUI(self):      self.name.set("")      self.province.set("")      self.city.set("")      self.street.set("")      self.zipcode.set("")

EditablePhone是Editable的另一個具體實現(xiàn),PIM使用它來處理個人電話號碼,其完整的代碼如清單4所示。

代碼清單4:editablephone.py  from editor import Editor  from editable import Editable  import Tkinter  class EditablePhone(Editable):    """ 用于處理個人電話號碼的Editable """        # 構(gòu)造函數(shù)    def __init__(self, master):      self.master =master      self.areaCode = "";      self.phoneNumber = ""     self.editor = PhoneEditor(self)          # 獲取相關(guān)聯(lián)的Editor    def getEditor(self):      return self.editor      class PhoneEditor(Editor, Tkinter.Frame):    """ 用于處理個人電話號碼的Editor """        # 構(gòu)造函數(shù)    def __init__(self, owner):      self.owner = owner      Tkinter.Frame.__init__(self, self.owner.master)      self.areaCode = Tkinter.StringVar()      self.phoneNumber = Tkinter.StringVar()      # 構(gòu)造用戶界面      codeLabel = Tkinter.Label(self, text="Area Code:")      codeEntry = Tkinter.Entry(self, textvariable=self.areaCode)      codeLabel.config(anchor=Tkinter.E, width=12, pady=3)      codeLabel.grid(row=0, column=0)      codeEntry.grid(row=0, column=1)            numberLabel = Tkinter.Label(self, text="Phone Number:")      numberEntry = Tkinter.Entry(self, textvariable=self.phoneNumber)      numberLabel.config(anchor=Tkinter.E, width=12, pady=3)      numberLabel.grid(row=1, column=0)      numberEntry.grid(row=1, column=1)          # 重載Editor中的方法,獲取代表用戶界面(UI)的對象    def getUI(self):      return self        # 重載Editor中的方法,獲取用戶輸入的數(shù)據(jù)    def getContent(self):      content  = "   Area Code: " + self.areaCode.get() + "\n"      content += "Phone Number: " + self.phoneNumber.get() + "\n"       return content       # 重載Editor中的方法,提交用戶輸入的數(shù)據(jù)    def commitChanges(self):      selfself.owner.areaCode = self.areaCode.get()      selfself.owner.phoneNumber = self.phoneNumber.get()          # 重載Editor中的方法,清空用戶輸入的數(shù)據(jù)    def resetUI(self):      self.areaCode.set("")      self.phoneNumber.set("")

EditableFactory接口是在PIM中應(yīng)用工廠方法模式的核心,其完整的代碼如清單5所示。與簡單工廠模式中負(fù)責(zé)創(chuàng)建所有對象的"超級類"不同,EditableFactory只定義了如何實例化Editable的工廠方法createEditable(),并不掌握它們的生殺大權(quán),真正負(fù)責(zé)完成創(chuàng)建工作的是EditableFactory的子類。

代碼清單5:editablefactory.py  class EditableFactory:    """ 用于創(chuàng)建Editable的工廠類 """        #  實例化Editable對象    def createEditable(self, master):      pass

EditableAddressFactory是EditableFactory的一個具體實現(xiàn),PIM使用它來實例化EditableAddress對象,其完整的代碼如清單6所示。

代碼清單6:editableaddressfactory.py  from editablefactory import EditableFactory  from editableaddress import EditableAddress  class EditableAddressFactory(EditableFactory):    """ 用于創(chuàng)建EditableAddress的工廠類 """        # 重載EditableFactory中的方法,實例化EditableAddress對象    def createEditable(self, master):      address = EditableAddress(master)      return address

EditablePhoneFactory是EditableFactory的另一個具體實現(xiàn),PIM使用它來實例化EditablePhone對象,其完整的代碼如清單7所示。

代碼清單7:editablephonefactory.py  from editablefactory import EditableFactory  from editablephone import EditablePhone  class EditablePhoneFactory(EditableFactory):    """ 用于創(chuàng)建EditablePhone的工廠類 """        # 重載EditableFactory中的方法,實例化EditablePhone對象    def createEditable(self, master):      phone = EditablePhone(master)      return phone

所有這些輔助類都定義好之后,接下去就可以編寫PIM類了,它提供了一個對各種個人信息進(jìn)行統(tǒng)一管理的框架,其完整的代碼如清單8所示。

代碼清單8:pim.py  from editablephone import EditablePhone  from editableaddressfactory import EditableAddressFactory  from editablephonefactory import EditablePhoneFactory  import Tkinter  class PIM:    """ 個人信息管理 """        # 構(gòu)造函數(shù)    def __init__(self):      mainFrame = Tkinter.Frame()          mainFrame.master.title("PIM")      # 命令按鈕      addressButton = Tkinter.Button(mainFrame, width=10, text="Address")      phoneButton = Tkinter.Button(mainFrame, width=10, text="Phone")      commitButton = Tkinter.Button(mainFrame, width=10, text="Commit")          resetButton = Tkinter.Button(mainFrame, width=10, text="Reset")              addressButton.config(command=self.addressClicked)      phoneButton.config(command=self.phoneClicked)          commitButton.config(command=self.commitClicked)              resetButton.config(command=self.resetClicked)              addressButton.grid(row=0, column=1, padx=10, pady=5, stick=Tkinter.E)      phoneButton.grid(row=1, column=1, padx=10, pady=5, stick=Tkinter.E)      commitButton.grid(row=2, column=1, padx=10, pady=5, stick=Tkinter.E)      resetButton.grid(row=3, column=1, padx=10, pady=5, stick=Tkinter.E)         # 用來容納各類Editor的容器      self.editorFrame = Tkinter.Frame(mainFrame)      self.editorFrame.grid(row=0, column=0, rowspan=4)      self.editorFrame.grid_configure(stick=Tkinter.N, pady=15)      self.editor = Tkinter.Frame(self.editorFrame)      self.editor.grid()         # 個人信息顯示區(qū)域      self.content = Tkinter.StringVar()      self.contentLabel = Tkinter.Label(mainFrame, width=50, height=5)      self.contentLabel.configure(textvariable=self.content)      self.contentLabel.configure(anchor=Tkinter.W, font="Arial 10 italic bold")      self.contentLabel.configure(relief=Tkinter.RIDGE, pady=5, padx=10)      self.contentLabel.grid(row=4, column=0, columnspan=2)            mainFrame.pack()      mainFrame.mainloop()          # Address按鈕的回調(diào)函數(shù)    def addressClicked(self):      address = EditableAddressFactory().createEditable(self.editorFrame)      self.editor.grid_remove()      self.editor = address.getEditor()      self.editor.getUI().grid()    # Phone按鈕的回調(diào)函數(shù)    def phoneClicked(self):      phone = EditablePhoneFactory().createEditable(self.editorFrame)      self.editor.grid_remove()      self.editor = phone.getEditor()      self.editor.getUI().grid()          # Commit按鈕的回調(diào)函數(shù)    def commitClicked(self):      content = self.editor.getContent()      self.content.set(content)        # Reset按鈕的回調(diào)函數(shù)    def resetClicked(self):      self.editor.resetUI()        # 主函數(shù)  if (__name__ == "__main__"):    app = PIM()

圖3是PIM在運(yùn)行時的界面效果。

Python中工廠方法模式有什么用

三、一般結(jié)構(gòu)

工廠方法模式是簡單工廠模式的進(jìn)一步抽象和推廣,它不僅保持了簡單工廠模式能夠向客戶隱藏類的實例化過程這一優(yōu)點,而且還通過多態(tài)性克服了工廠類過于復(fù)雜且不易于擴(kuò)展的缺點。在工廠方法模式中,處于核心地位的工廠類不再負(fù)責(zé)所有產(chǎn)品的創(chuàng)建,而是將具體的創(chuàng)建工作交由子類去完成。工廠方法模式中的核心工廠類經(jīng)過功能抽象之后,成為了一個抽象的工廠角色,僅負(fù)責(zé)給出具體工廠子類必須實現(xiàn)的接口,而不涉及哪種產(chǎn)品類應(yīng)當(dāng)被實例化這一細(xì)節(jié)。工廠方法模式的一般性結(jié)構(gòu)如圖4所示,圖中為了簡化只給出了一個產(chǎn)品類和一個工廠類,但在實際系統(tǒng)中通常需要設(shè)計多個產(chǎn)品類和多個工廠類。

Python中工廠方法模式有什么用

工廠方法模式的實質(zhì)是將對象的創(chuàng)建延遲到其子類實現(xiàn),即由子類根據(jù)當(dāng)前情況動態(tài)決定應(yīng)該實例化哪一個產(chǎn)品類。從上圖可以看出,工廠方法模式涉及到抽象工廠角色、具體工廠角色、抽象產(chǎn)品角色和具體產(chǎn)品角色四個參與者。

◆抽象工廠(Creator)角色:是工廠方法模式的核心,它負(fù)責(zé)定義創(chuàng)建抽象產(chǎn)品對象的工廠方法。抽象工廠不能被外界直接調(diào)用,但任何在模式中用于創(chuàng)建產(chǎn)品對象的工廠類都必須實現(xiàn)由它所定義的工廠方法。

具體工廠(Concrete Creator)角色:是工廠方法模式的對外接口,它負(fù)責(zé)實現(xiàn)創(chuàng)建具體產(chǎn)品對象的內(nèi)部邏輯。具體工廠與應(yīng)用密切相關(guān),可以被外界直接調(diào)用,創(chuàng)建所需要的產(chǎn)品。

抽象產(chǎn)品(Product)角色:是工廠方法模式所創(chuàng)建的所有對象的父類,它負(fù)責(zé)描述所有具體產(chǎn)品共有的公共接口。

具體產(chǎn)品(Concrete Product)角色:是工廠方法模式的創(chuàng)建目標(biāo),所有創(chuàng)建的對象都是充當(dāng)這一角色的某個具體類的實例。

抽象工廠角色負(fù)責(zé)聲明工廠方法(factory method),用來"生產(chǎn)"抽象產(chǎn)品,以下是抽象工廠的示例性Python代碼:

代碼清單9:creator.py  class Creator:    """ 抽象工廠角色 """        # 創(chuàng)建抽象產(chǎn)品的工廠方法    def factoryMethod(self):      pass

具體工廠角色負(fù)責(zé)創(chuàng)建一個具體產(chǎn)品的實例,并將其返回給調(diào)用者。具體工廠是與具體產(chǎn)品相關(guān)的,實現(xiàn)時一般常用的做法是為每個具體產(chǎn)品定義一個具體工廠。以下是具體工廠的示例性Python代碼:

代碼清單10:concretecreator.py  class ConcreteCreator(Creator):    """ 具體工廠角色 """        # 創(chuàng)建具體產(chǎn)品的工廠方法    def factoryMethod(self):      product =  ConcreteProduct()      return product

抽象產(chǎn)品角色的主要目的是為所有的具體產(chǎn)品提供一個共同的接口,通常只需給出相應(yīng)的聲明就可以了,而不用給出具體的實現(xiàn)。以下是抽象產(chǎn)品類的示例性Python代碼:

代碼清單11:product.py  class Product:    """ 抽象產(chǎn)品角色 """        # 所有產(chǎn)品類的公共接口    def interface(self):      pass

具體產(chǎn)品角色充當(dāng)最終的創(chuàng)建目標(biāo),一般來講它是抽象產(chǎn)品類的子類,實現(xiàn)了抽象產(chǎn)品類中定義的所有工廠方法,實際應(yīng)用時通常會具有比較復(fù)雜的業(yè)務(wù)邏輯。以下是具體產(chǎn)品類的示例性Python代碼:

代碼清單12:concreteproduct.py  class ConcreteProduct(Product):    """ 具體產(chǎn)品角色 """        # 公共接口的實現(xiàn)    def interface(self):      print "Concrete Product Method"


在應(yīng)用工廠方法模式時,通常還需要再引入一個客戶端角色,由它負(fù)責(zé)創(chuàng)建具體的工廠對象,然后再調(diào)用工廠對象中的工廠方法來創(chuàng)建相應(yīng)的產(chǎn)品對象。以下是客戶端的示例性Python代碼:

代碼清單13:client.py  class Client:    """ 客戶端角色 """        def run(self):      creator = ConcreteCreator()      product = creator.factoryMethod()      product.interface()  # 主函數(shù)  if (__name__ == "__main__"):    client = Client()    client.run()


在這個簡單的示意性實現(xiàn)里,充當(dāng)具體產(chǎn)品和具體工廠角色的類都只有一個,但在真正的實際應(yīng)用中,通常遇到的都是同時會有多個具體產(chǎn)品類的情況,此時相應(yīng)地需要提供多個具體工廠類,每個具體工廠都負(fù)責(zé)生產(chǎn)對應(yīng)的具體產(chǎn)品。

工廠方法模式的活動序列如圖5所示,客戶端Client首先創(chuàng)建ConcreteCreator對象,然后調(diào)用ConcreteCreator對象的工廠方法factoryMethod(),由它負(fù)責(zé)"生產(chǎn)"出所需要的ConcreteProduct對象。

Python中工廠方法模式有什么用

四、實際運(yùn)用

使用工廠方法模式可以在不修改具體工廠角色的情況下引入新的產(chǎn)品,這一點無疑使得工廠方法模式具有比簡單工廠模式更好的可擴(kuò)展性。在開發(fā)實際的軟件系統(tǒng)時,通常是先設(shè)計產(chǎn)品角色,然后才開始設(shè)計工廠角色,而復(fù)雜的需求導(dǎo)致將在抽象產(chǎn)品和具體產(chǎn)品之間形成非常龐大的樹狀結(jié)構(gòu),如圖6所示。

Python中工廠方法模式有什么用

在上面的產(chǎn)品等級結(jié)構(gòu)中,出現(xiàn)了多于一個的抽象產(chǎn)品類,以及多于兩個的類層次,這是在構(gòu)造真實系統(tǒng)中經(jīng)常遇到的情況。在為這一軟件體系結(jié)構(gòu)應(yīng)用工廠方法模式時,通常的做法是按照產(chǎn)品的等級結(jié)構(gòu)再設(shè)計一個相同的工廠等級結(jié)構(gòu),如圖7所示。

Python中工廠方法模式有什么用

定義工廠角色的目的是為了創(chuàng)建相應(yīng)的產(chǎn)品角色,因此整個系統(tǒng)的架構(gòu)將如圖8所示。這一結(jié)構(gòu)常常被稱為平行的類層次(parallel class hierarchies),它使得一個類能夠?qū)⑺囊恍┞氊?zé)委托給另一個獨立的類,而工廠方法則是聯(lián)系兩者之間的紐帶。工廠方法模式并沒有限制產(chǎn)品等級的層數(shù),雖然前面給出的一般性結(jié)構(gòu)中只有兩個層次(抽象產(chǎn)品層和具體產(chǎn)品層),但在實際運(yùn)用時卻往往需要更加復(fù)雜的產(chǎn)品層次。

Python中工廠方法模式有什么用

在工廠方法模式的一般性結(jié)構(gòu)中,每當(dāng)具體工廠類中的工廠方法被請求時,都會調(diào)用具體產(chǎn)品類的構(gòu)造函數(shù)來創(chuàng)建一個新的產(chǎn)品實例,然后再將這個實例提供給客戶端。但在實際軟件系統(tǒng)中應(yīng)用工廠方法模式時,工廠方法所做的事情可能更加復(fù)雜,其中最常見到的一種情況是循環(huán)使用產(chǎn)品對象。所采用的策略是將工廠對象創(chuàng)建的所有產(chǎn)品對象登記到一個對象池(object pool)中,這樣每當(dāng)客戶請求工廠方法創(chuàng)建相應(yīng)的產(chǎn)品對象時,可以先從對象池中查詢符合條件的產(chǎn)品對象,如果對象池中恰巧有這樣的對象,那就直接將這個產(chǎn)品對象返回給客戶端;如果對象池中沒有這樣的對象,那就創(chuàng)建一個新的滿足要求的產(chǎn)品對象,將其登記到對象池中,然后再返回給客戶端。

工廠方法模式依賴于工廠角色和產(chǎn)品角色的多態(tài)性,但在實際運(yùn)用時這個模式可能出現(xiàn)退化,其表現(xiàn)就是多態(tài)性的喪失。在工廠方法模式中,所有的具體工廠對象應(yīng)該共享一個抽象的超類,或者換句話說,應(yīng)當(dāng)有多個具體工廠類作為一個抽象工廠類的子類存在于工廠等級結(jié)構(gòu)中,但如果工廠等級結(jié)構(gòu)中只有一個具體工廠類的話,那么抽象工廠角色可以省略。當(dāng)抽象工廠角色被省略時,工廠方法模式就發(fā)生了退化,這一退化表現(xiàn)為工廠角色多態(tài)性的喪失,退化后的模式仍然可以發(fā)揮部分工廠方法模式的作用,通常被稱為退化的工廠方法模式。退化的工廠方法模式在很大程度上與簡單工廠模式相似,如圖9所示,實際運(yùn)用時可以考慮用簡單工廠模式進(jìn)行替代。

Python中工廠方法模式有什么用

在工廠方法模式中,從工廠方法返回的應(yīng)當(dāng)是抽象產(chǎn)品類型,而不是具體產(chǎn)品類型,因為只有這樣才能保證產(chǎn)品角色的多態(tài)性。也就是說,調(diào)用工廠方法的客戶端可以針對抽象產(chǎn)品類進(jìn)行編程,而不必依賴于具體產(chǎn)品類。在實際運(yùn)用時有可能會出現(xiàn)一種很特殊的情況,那就是工廠方法只需要返回一個具體產(chǎn)品類,此時工廠方法模式的功能同樣會發(fā)生退化,但這一退化將表現(xiàn)為產(chǎn)品角色多態(tài)性的喪失,如圖10所示。嚴(yán)格說來,當(dāng)工廠方法模式出現(xiàn)這一退化時,就不能再稱為工廠方法模式了,因為客戶端從工廠方法的靜態(tài)類型就可以判斷出將要得到的是什么類型的對象,而這一點恰好違背了工廠方法模式的初衷。

Python中工廠方法模式有什么用

五、優(yōu)勢和不足

在工廠方法模式中,工廠方法用來創(chuàng)建客戶所需要的產(chǎn)品,同時還向客戶隱藏了哪種具體產(chǎn)品類將被實例化這一細(xì)節(jié)。工廠方法模式的核心是一個抽象工廠類,各種具體工廠類通過從抽象工廠類中將工廠方法繼承下來,使得客戶可以只關(guān)心抽象產(chǎn)品和抽象工廠,完全不用理會返回的是哪一種具體產(chǎn)品,也不用關(guān)心它是如何被具體工廠創(chuàng)建的。

基于工廠角色和產(chǎn)品角色的多態(tài)性設(shè)計是工廠方法模式的關(guān)鍵,它使得工廠可以自主確定創(chuàng)建何種產(chǎn)品對象,而如何創(chuàng)建這個對象的細(xì)節(jié)則完全封裝在具體工廠內(nèi)部。工廠方法模式之所以又被稱為多態(tài)工廠模式,顯然是因為所有的具體工廠類都具有同一抽象父類。

使用工廠方法模式的另一個優(yōu)點是在系統(tǒng)中加入新產(chǎn)品時,不需要對抽象工廠和抽象產(chǎn)品提供的接口進(jìn)行修改,而只要添加一個具體工廠和具體產(chǎn)品就可以了,沒有必要修改客戶端,也沒有必須修改其他的具體工廠和具體產(chǎn)品,系統(tǒng)的可擴(kuò)展性非常好。優(yōu)秀的面向?qū)ο笤O(shè)計鼓勵使用封裝(Encapsulation)和委托(Delegation)來構(gòu)造軟件系統(tǒng),而工廠方法模式則是使用了封裝和委托的典型例子,其中封裝是通過抽象工廠來體現(xiàn)的,而委托則是通過抽象工廠將創(chuàng)建對象的責(zé)任完全交給具體工廠來體現(xiàn)的。

使用工廠方法模式的缺點是在添加新產(chǎn)品時,需要編寫新的具體產(chǎn)品類,而且還要提供與之對應(yīng)的具體工廠類,當(dāng)兩者都比較簡單時,系統(tǒng)的額外開銷相對較大。

以上是“Python中工廠方法模式有什么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


分享題目:Python中工廠方法模式有什么用
當(dāng)前網(wǎng)址:http://weahome.cn/article/jogcgh.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部