一起来学设计模式-----创建型模式之简单工厂
一直都特别想整体学习下设计模式,之前总觉得不是时候,觉得基础不够好怕吸收不了,或者体会不到设计模式带来的便利。就在上半年的KPI编写测试桩项目中,我就深刻的感受到设计模式带来的好处。一般测试人员写的代码不是很多,很多时候写代码也都是基于解决问题的逻辑来的,写的代码面向过程思路较多,因此代码的冗余度特别大。在编写一个大的测试工具时,就更应该考虑这方面的问题自己是否存在。刻不容缓的学习起了设计模式,整理就从创建型模式的工厂模式开始入手吧。
创建型模式,共三种:工厂方法模式、建造者模式、原型模式。其中工厂模式,又分简单工厂,工厂方法,和抽象工厂三类。创建型模式,基于现在我对这个概念的理解,主要就是用来获取对象的。这一章主要是总结简单工厂的实现和优缺点。
现在需要实现一个计算功能,做一个能实现加减乘除的小程序。最开始应该是这样写的:
def operate(a,b,op): if op =='+': return a+b elif op =='-': return a-b elif op =='*': return a*b elif op== '/': return a/b else: return 'op error!' if __name__ == '__main__': print operate(2,2,'+')
我得承认,大部分时候我写的脚本都是这样的,单从测试的角度就有1个bug(除法计算未考虑分子为0的情况),从设计角度上就有更大的缺陷,只满足了面向对象的一个特征(封装),还有继承和抽象完成没有考虑,如果再增加一个N的平方的计算,得改动所有的代码。彻底的违背了设计的开发-关闭原则(对扩展开放,对修改关闭)。
使用设计的模式来考虑,首先无论何种运算,都是实现2个数之间的运算。可以由此抽象出一个基类BaseOperation
class BaseOperation: def GetResult(self,a,b): result = 0 return result
在此基础上,其他的运算都继承实现各自的特定计算,根据需求重写GetResult
class OperationAdd(BaseOperation): def __int__(self,a,b): self.a = a self.b = b def GetResult(self,a,b): result = 0 result = a + b return result class OperationSub(BaseOperation): def __int__(self,a,b): self.a = a self.b = b def GetResult(self,a,b): result = 0 result = a - b return result class OperationMul(BaseOperation): def GetResult(self,a,b): result = 0 result = a * b return result class OperationDiv(BaseOperation): def GetResult(self,a,b): result = 0 if b == 0 : raise ValueError("no 0 !") result = a/b return result
最后一个方法封装调用的逻辑给客户端生成对象使用,客户端传需要的操作,就能得到相应实例。如下所示:
def OperationFactory(operate): oper = None if operate == '+': oper = OperationAdd() elif operate == '-': oper = OperationSub() elif operate == '*': oper = OperationMul() elif operate == '/': oper = OperationDiv() else: raise ValueError("only support + - * /") return oper
客户端调用如下:
def main(): oper = OperationFactory('/') print oper.GetResult(3,0) if __name__=='__main__': main()
这样实现后,如果需要再增加一个运算,改动量就相对少了些,客户端不需要修改,只需要传递不同的入参,服务端编写一个类,增加工厂方法对应的处理即可。一个简单的工厂方法模式就诞生了,简单工厂,它是一个方法,或者说就是一个函数,对不同的输入参数返回不同的对象uml类图如下:
总结下:
简单工厂模式总结
优点:
在于工厂类中包含了必要的逻辑判断,需要根据客户端的选择条件动态的实例化相关的类,对于客户端来说,去除与具体产品的依赖,客户端不管是哪个类,只需要把自己知道的参数传递给工厂,工厂就会给出响应的实例,客户端只需要拿着实例调用接口即可。
缺点:
如果需要新增一个类,则需要修改工厂类的case的分支,修改原有的类,这样违背了“开放-封闭”原则