23种设计模式——简单工厂模式(python版)

简单工厂模式

现实生活中,原始社会自给自足(没有工厂),农耕社会小作坊(简单工厂,民间酒坊),工业革命流水线(工厂方法,自产自销),现代产业链代工厂(抽象工厂,富士康)。我们的项目代码同样是由简到繁一步一步迭代而来的,但对于调用者来说,却越来越简单。

在日常开发中,凡是需要生成复杂对象的地方,都可以尝试考虑使用工厂模式来代替。
注意:上述复杂对象指的是类的构造函数参数过多等对类的构造有影响的情况,因为类的构造过于复杂,如果直接在其他业务类内使用,则两者的耦合过重,后续业务更改,就需要在任何引用该类的源代码内进行更改,光是查找所有依赖就很消耗时间了,更别说要一个一个修改了。

工厂模式的定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。

按实际业务场景划分,工厂模式有 3 种不同的实现方式,分别是简单工厂模式、工厂方法模式和抽象工厂模式。

我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”。

在简单工厂模式中创建实例的方法通常为静态(static)方法,因此简单工厂模式(Simple Factory Pattern)又叫作静态工厂方法模式(Static Factory Method Pattern)。

简单来说,简单工厂模式有一个具体的工厂类,可以生成多个不同的产品,属于创建型设计模式。简单工厂模式不在 GoF 23 种设计模式之列。

简单工厂模式每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度,违背了“开闭原则”。
“工厂方法模式”是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。

优点和缺点

优点:

工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
客户端无需知道所创建具体产品的类名,只需知道参数即可。
也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类。

缺点:

简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。
应用场景
对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。
模式的结构与实现

简单工厂模式的主要角色如下:

简单工厂(SimpleFactory):是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
抽象产品(Product):是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。
具体产品(ConcreteProduct):是简单工厂模式的创建目标。

其结构图如下图所示。
在这里插入图片描述

简单工厂模式实现

下面考虑《大话设计模式》中的一个例子:

题目:用任意一种面向对象语言实现一个计算器控制台程序。要求输入两个数和运算符号,得到结果。
题目分析:
程序应该做到:(1)可维护;(2)可复用;(3)可扩展;(4)灵活性好。
可维护:就是说代码一处更改,不能产生连锁反应,不能影响其他地方。
可复用:尽量减少重复性代码。
可扩展:如果要扩展新的功能、新的业务,则只需要增加新的类就好了,不对已有的类和逻辑产生影响。插拔式的应用。

面向对象要点:
面向对象三大特性:封装、继承、多态。
通过封装、继承、多态把程序耦合降低。
业务逻辑和界面逻辑分开。

类的结构图:

在这里插入图片描述
代码实现:

  1. 首先,搞清楚业务中容易发生变化的部分。在本应用中,要求计算两个数的运算结果,那么要进行什么样的运算,这就是一个容易发生变化的部分。例如,我们现在只想实现加减乘除运算,后期又想增加开根或者求余运算。那么如何应对这种需求带来的变化。在程序设计的时候就应该考虑到程序的可维护性、可扩展性、代码的可复用性、灵活性等等。

  2. 例如现在这个运算器只有加减乘除四种运算。首先建一个Operation类,这个类是各种具体运算类(加减乘除)的父类,主要是接受用户输入的数值。该类如下:

class Operation():
	def __init__(self,NumberA=0,NumberB=0):
		self.NumberA = NumberA
		self.NumberB = NumberB
 
	def GetResult(self):
		pass
  1. 然后是具体的运算类:Add、Sub、Mul、Div。他们都继承了Operation类,并且重写了getResult()方法。这样就可以用多态性降低不同业务逻辑的耦合度,修改任何一种运算类都不会影响其他的运算类。具体类的代码如下:

class AddOp(Operation):
	def GetResult(self):
		return self.NumberB + self.NumberA
 
class MinusOp(Operation):
	def GetResult(self):
		return self.NumberA - self.NumberB
 
class MultiOp(Operation):
	def GetResult(self):
		return self.NumberA * self.NumberB
 
class DivideOp(Operation):
	def GetResult(self):
		try:
			return 1.0*self.NumberA / self.NumberB
		except ZeroDivisionError:
			raise

  1. 那么如何让计算器知道我是要用哪一种运算呢?也就是说到底要实例化哪一个具体的运算类,Add?Sub?Mul?Div?这时就应该考虑用 一个单独的类来做这个创造具体实例的过程,这个类就是工厂类。如下:

class OperationFatory():
	def ChooseOperation(self,op):
		if op == '+':
			return AddOp()
		if op == '-':
			return MinusOp()
		if op == '*':
			return MultiOp()
		if op == '/':
			return DivideOp()
  1. 这样,用户只要输入运算符,工厂类就可以创建合适的实例,通过多态性,即返回给父类的方式实现运算结果。客户端代码如下:

if __name__ == '__main__':
	ch = ''
	while not ch=='q': 
		NumberA = eval(raw_input('Please input number1:  '))
		op = str(raw_input('Please input the operation:  '))
		NumberB = eval(raw_input('Please input number2:  '))
		OPFactory = OperationFatory()
		OPType = OPFactory.ChooseOperation(op)
		OPType.NumberA = NumberA
		OPType.NumberB = NumberB
		print 'The result is:',OPType.GetResult()
		print '\n#--  input q to exit any key to continue'
		try:
			ch = str(raw_input())
		except:
			ch = ''

完整版代码如下

# -*-coding:UTF-8-*-  
from abc import ABCMeta,abstractmethod
 
class Operation():
	def __init__(self,NumberA=0,NumberB=0):
		self.NumberA = NumberA
		self.NumberB = NumberB
 
	def GetResult(self):
		pass
 
class AddOp(Operation):
	def GetResult(self):
		return self.NumberB + self.NumberA
 
class MinusOp(Operation):
	def GetResult(self):
		return self.NumberA - self.NumberB
 
class MultiOp(Operation):
	def GetResult(self):
		return self.NumberA * self.NumberB
 
class DivideOp(Operation):
	def GetResult(self):
		try:
			return 1.0*self.NumberA / self.NumberB
		except ZeroDivisionError:
			raise
 
class OperationFatory():
	def ChooseOperation(self,op):
		if op == '+':
			return AddOp()
		if op == '-':
			return MinusOp()
		if op == '*':
			return MultiOp()
		if op == '/':
			return DivideOp()
 
if __name__ == '__main__':
	ch = ''
	while not ch=='q': 
		NumberA = eval(raw_input('Please input number1:  '))
		op = str(raw_input('Please input the operation:  '))
		NumberB = eval(raw_input('Please input number2:  '))
		OPFactory = OperationFatory()
		OPType = OPFactory.ChooseOperation(op)
		OPType.NumberA = NumberA
		OPType.NumberB = NumberB
		print 'The result is:',OPType.GetResult()
		print '\n#--  input q to exit any key to continue'
		try:
			ch = str(raw_input())
		except:
			ch = ''
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值