[Python设计模式] 第8章 学习雷锋好榜样——工厂方法模式
github地址:https://github.com/cheesezh/python_design_patterns
簡單工廠模式 v.s. 工廠方法模式
以簡單計算器為例,對比一下簡單工廠模式和工廠方法模式的區別。
簡單工廠模式
from abc import ABCMeta, abstractmethodclass Operation():"""抽象產品類(運算符類)"""__metaclass__ = ABCMetadef __init__(self):self.result = None@abstractmethoddef get_result(self):passclass AddOperation(Operation):"""具體產品類(加法運算符)"""def get_result(self, number_a, number_b):self.result = number_a + number_breturn self.resultclass SubOperation(Operation):"""具體產品類(減法運算符)"""def get_result(self, number_a, number_b):self.result = number_a - number_breturn self.resultclass MulOperation(Operation):"""具體產品類(乘法運算符)"""def get_result(self, number_a, number_b):self.result = number_a * number_breturn self.resultclass DivOperation(Operation):"""具體產品類(除法運算符)"""def get_result(self, number_a, number_b):if number_b == 0:print("With operator '/', the second number can not be zero.")return self.resultself.result = number_a / number_breturn self.resultclass OperationFactory():"""產品工廠類"""@classmethoddef create_operate(self, operator):oper = Noneif operator == "+":oper = AddOperation()elif operator == "-":oper = SubOperation()elif operator == "*":oper = MulOperation()elif operator == "/":oper = DivOperation()else:print("Wrong operator.")return opernumber_a = int(input("input a number:")) operator = str(input("input a operater(+ - * /):")) number_b = int(input("input a number:"))oper = OperationFactory.create_operate(operator) print(oper.get_result(number_a, number_b)) input a number:99 input a operater(+ - * /):/ input a number:9 11.0工廠方法模式
from abc import ABCMeta, abstractmethodclass IFactory():"""通用工廠接口"""__metaclass__ = ABCMeta@abstractmethoddef create_operation(self):passclass AddFactory(IFactory):"""實現工廠接口的加法工廠類"""def create_operation(self):return AddOperation()class SubFactory(IFactory):"""實現工廠接口的劍法工廠類"""def create_operation(self):return SubOperation()class MulFactory(IFactory):"""實現工廠接口的乘法工廠類"""def create_operation(self):return MulOperation()class DivFactory(IFactory):"""實現工廠接口的除法工廠類"""def create_operation(self):return DivOperation()def main():number_a = int(input("input a number:"))operator = str(input("input a operater(+ - * /):"))number_b = int(input("input a number:"))if operator == "+":oper_factory = AddFactory()elif operator == "-":oper_factory = SubFactory()elif operator == "*":oper_factory = MulFactory()elif operator == "/":oper_factory = DivFactory()else:print("Wrong operator.")oper = oper_factory.create_operation()print(oper.get_result(number_a, number_b))main() input a number:99 input a operater(+ - * /):/ input a number:11 9.0點評
工廠方法更復雜了?
如果需要增加其他運算,比如求M的N次方。
在簡單工廠模式里,先增加一個求M的N次方的產品類,然后更改工廠類的if判斷增加分支即可。
在工廠方法模式里,先增加一個求M的N次方的產品類,還要新增一個相關工廠類,最后還有修改客戶端代碼。
這就是簡單工廠和工廠方法的區別所在。簡單工廠模式的最大優點在于工廠類中包含了必要的邏輯判斷,根據客戶端的選擇條件動態實例化相關類,對于客戶端來說,去除了與具體產品的依賴。但是,如果要增加一個新的功能,比如求M的N次方,需要更改工廠類的if判斷分支條件,修改原有的類?違背了開放-封閉原則,這可不是好方法。所以就需要工廠方法模式來處理。
工廠方法模式
工廠方法模式,定義一個用于創建對象的接口,讓子類決定實例化哪一個類。工廠方法使一個類的實例化延遲到其子類[DP]。
相當于將簡單工廠中的工廠類,變成了一個工廠抽象接口和多個具體生成對象的工廠,于是我們要增加求M的N次方的功能,就不需要更改工廠類,只需要增加此功能的運算類和相應的工廠類即可。這樣整個工廠和產品體系其實都沒有修改,而只是擴展,這就完全符合了開放-封閉原則。
但是,工廠方法模式是現實,客戶端需要決定實例化哪一個工廠來實現運算類,選擇判斷的問題還是存在的,也就是說,工廠方法把簡單工廠的內部邏輯判斷移到了客戶端代碼來進行。要增加新功能,本來修改工廠類,現在修改客戶端了。
題目
木葉學校組織學雷鋒活動,讓鳴人,小櫻,佐助幫敬老院的老人掃地,洗衣,買米,如何實現?
class LeiFeng():def sweep(self):print("掃地")def wash(self):print("洗衣")def buy_rice(self):print("買米")class Student(LeiFeng):passdef main():mingren = Student()xiaoying = Student()zuozhu = Student()mingren.sweep()xiaoying.wash()zuozhu.buy_rice() main() 掃地 洗衣 買米點評
- 學生都會畢業,但是幫助老人是長期工作,所以每次不同的人幫助老人,都需要改客戶端代碼,而且老人不可能知道所有來幫忙的學生的名字;
- 除了學生,社區志愿者也可以幫助老人
如何用簡單工廠方法解決上述問題?
class Volunteer(LeiFeng):passclass SimpleFactory():@classmethoddef create_leifeng(self, leifeng_type):self.leifeng = Noneif leifeng_type == "學生":self.leifeng = Student()elif leifeng_type == "志愿者":self.leifeng = Volunteer()else:print("ERROR LeiFeng Type")return self.leifengdef main():studentA = SimpleFactory.create_leifeng("學生")studentA.buy_rice()studentB = SimpleFactory.create_leifeng("學生")studentB.wash()studentC = SimpleFactory.create_leifeng("學生")studentB.sweep()main() 買米 洗衣 掃地點評
- 好的地方,客戶端的代碼,如果要換志愿者,只需要換參數即可;
- 壞的地方,在任何實例化的時候都需要寫一句SimpleFactory.create_leifeng("學生"),這會導致大量重復,在修改為志愿者的時候非常麻煩,可以用工廠方法解決這個問題;
點評
- 此時如果要將學生改成志愿者,只需要修改一行代碼即可;
- 工廠方法克服了簡單工廠違背開放-封閉原則的缺點,又保持了封裝對象創建過程的優點;
總結
簡單工廠和工廠方法都是集中封裝了對象的創建,使得要更換對象時,不需要做大的改動就可以實現,降低了客戶程序和產品對象的耦合。
工廠方法是簡單工廠模式的進一步抽象和推廣,由于使用了多態性,工廠方法模式保持了簡單工廠模式的優點,而且克服了它的缺點。但缺點是由于每加一個產品,就需要加一個產品工廠類,增加了額外開發量。
另外,工廠方法還是沒有避免修改客戶端的代碼,可以利用反射解決避免分支判斷的問題。
轉載于:https://www.cnblogs.com/CheeseZH/p/9392938.html
總結
以上是生活随笔為你收集整理的[Python设计模式] 第8章 学习雷锋好榜样——工厂方法模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑小常识----文件名长度过长解决办法
- 下一篇: 在命令行中的vim编辑器加上行号