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("学生"),这会导致大量重复,在修改为志愿者的时候非常麻烦,可以用工厂方法解决这个问题;
from abc import ABCMeta, abstractmethodclass ILeiFengFactory():__metaclass__ = ABCMeta@abstractmethoddef create_leifeng(self):passclass StudentFactory(ILeiFengFactory):def create_leifeng(self):return Student()class VolunteerFactory(ILeiFengFactory):def create_leifeng(self):return Volunteer()def main():leifeng_factory = StudentFactory()stu1 = leifeng_factory.create_leifeng()stu2 = leifeng_factory.create_leifeng()stu3 = leifeng_factory.create_leifeng()stu1.sweep()stu2.wash()stu3.buy_rice()main()
扫地
洗衣
买米

点评

  • 此时如果要将学生改成志愿者,只需要修改一行代码即可;
  • 工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点;

总结

简单工厂和工厂方法都是集中封装了对象的创建,使得要更换对象时,不需要做大的改动就可以实现,降低了客户程序和产品对象的耦合。

工厂方法是简单工厂模式的进一步抽象和推广,由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。但缺点是由于每加一个产品,就需要加一个产品工厂类,增加了额外开发量。

另外,工厂方法还是没有避免修改客户端的代码,可以利用反射解决避免分支判断的问题。

转载于:https://www.cnblogs.com/CheeseZH/p/9392938.html

[Python设计模式] 第8章 学习雷锋好榜样——工厂方法模式相关推荐

  1. 设计模式学习-工厂方法模式

    在上文(设计模式学习-简单工厂模式)的模拟场景中,我们用简单工厂模式实现了VISA和MASTERARD卡的刷卡处理,系统成功上线并运行良好,突然有一天老大跑来说,我们的系统需要升级,提供对一般银联卡的 ...

  2. 【设计模式学习】工厂方法模式

    cpp学习设计模式:工厂方法模式 在学习工厂方法模式之前,先回忆前面学的简单工厂模式: 简单工厂模式就是将对象的创建和逻辑的判断都交给了一个工厂类去做,这样做的优点是客户端不需要知道具体产品类的类名和 ...

  3. 软件工程 - 设计模式学习之工厂方法模式Factory Method

    在现实生活中我们可以看见,乐事在卖薯片,可比克也在卖. 我敢肯定的说它们各自都有自己的工厂来生产薯片,而且生产出来的薯片味道还是不一样的. 这就是我们这里所谓的工厂方法模式. 我们来看看这个模式的UM ...

  4. java简单工厂模式实例造车,JAVA设计模式学习5——工厂方法模式

    工厂方法模式(Factory Method)又称虚拟构造子模式,可以说是简单工厂的抽象,也可以理解为简单工厂是退化了的工厂方法模式,其表现在简单工厂丧失了工厂方法的多态性.我们前一节中提到当产品结构变 ...

  5. JAVA设计模式是个什么玩意儿_01_工厂方法模式

    1. 前言 工厂方法模式(Factory Method) 该模式属于创建型设计模式. 2. 定义 摘自<研磨设计模式> 陈臣.王斌 3.代码举例 public interface BMW ...

  6. Android源码学习之工厂方法模式应用

    主要内容: 工厂方法模式定义 工厂方法模式优势 工厂方法模式在Android源码中的应用 一.工厂方法模式定义 工厂方法模式定义: Define an interface for creating a ...

  7. 设计模式系列漫谈之二 - 工厂方法模式

    故事       10月1日是小雪的生日.许多追求者都想在生日那天给小雪一份意想不到的惊喜,并且表达自己的爱意.这些追求者绞尽脑汁的为小雪发送一个比较有创意的祝福短信.看来,小雪今年的生日过得肯定非常 ...

  8. 设计模式来一发(三)工厂方法模式

    1.定义 为某个对象提供一个接口,而且无需指定它们的具体类. 工厂方法模式,是简单工厂模式的延伸(https://blog.csdn.net/ss1300460973/article/details/ ...

  9. 大话设计模式读书 笔记(六) 工厂方法模式

    工厂方法模式(Factory Method) 书中通过一个学雷锋的例子,来引出工厂方法模式. 工厂方法模式:定义了一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类 ...

最新文章

  1. embed的名词_常见名词解释
  2. Deepin系统安装
  3. 分享云及人工智能的一些学习资源和学习心得
  4. html页面加载转圈,纯CSS实现加载转圈样式
  5. linux 两个驱动 竞态,第7章 Linux设备驱动中的并发控制之一(并发与竞态)
  6. matlab打开界面模糊,如何在人机界面GUI的M文件中嵌入模糊FIS模块
  7. ip地址转换数字函数 iton_DataLakeAnalytics: 解析IP地址对应的国家城市的函数
  8. leetcode刷题 2.两数相加
  9. python搭建环境教程_python教程(一)·python环境搭建
  10. 第5章分布式系统模式 Broker(代理程序)
  11. 机器学习必看的28个视频
  12. SQL基础系列(三)——分组查询
  13. 基于Jtopo的网络拓扑编辑器初探
  14. Android WebView 因重定向无法正常goBack()的一种解决小方案
  15. QCC305X-QCC304x系列开发教程(系统篇)之3.4-Mirroring详解
  16. 虚拟化系统(XenServer,ESXi)-XenServer
  17. 无名管道(pipe)--实现管道双向通信
  18. 巧学五笔打字-----1小时可学会,不用死背字根 [图片]
  19. Windows--UEFI引导安装Win10
  20. 教你科学实施有氧运动

热门文章

  1. 安川g7接线端子图_ABB、KUKA、FANUC、安川四大家族机器人安全回路小结
  2. eclipse:解决修改文件需要重启tomcat问题
  3. liferay 采用URL方式传值
  4. 我的新书《Java编程讲义》新鲜出炉啦,欢迎订阅
  5. bat/cmd将命令执行的结果赋值给变量
  6. Elasticsearch教程elasticsearch Client创建
  7. linux的lsof命令详解
  8. 详解log4j2(下) - 按日志级别区分文件输出
  9. Gradient Boosted Decision Trees详解
  10. 关于SparkMLlib的基础数据结构Spark-MLlib-Basics