我的运行环境是Python3.4.2。以下代码都能运行成功。
我们通过面向过程,逐步过渡到面向对象,让我们领略面向对象的魅力。
这是我在学习的第一个设计模式,也是最简单的一种设计模式。简单工厂模式时一种最简单的创建型设计模式,其目的是将对象创建和使用解耦。
我们一般都会习惯性的分析问题所需的步骤,然后用函数把这些步骤逐步实现,使用的时候在依次调用。
以计算器为例。面向过程就是:输入两个数字和一个运算符,然后根据输入的运算符,实现运算,然后结果。
第一版---初学者代码毛病
#!/usr/bin/env python
if __name__ == '__main__':
A=input("请输入数字A: ")
B=input("请选择运算符(+|-|*|/): ")
C=input("请输入数字B: ")
if(B == '+'):
D = float(A) + float(C)
if(B == '-'):
D = float(A) - float(C)
if(B == '*'):
D = float(A) * float(C)
if(B == '/'):
D = float(A) / float(C)
print("结果是: ",D)
以上代码有三个问题:
- 问题一:变量命名不规范
- 问题二:判断分支,这样每次运算都要做三次无用的判断
- 问题三:重复代码多,性能和内存使用率低
- 问题四:复用性差,想复用就要重新拷贝代码
- 使用规范变量名
- 将每种运算类型封装成函数
- 利用字典,取代if-else的分支判断,减少无用判断
- 增加了异常捕获机制,代码更加健壮
#!/usr/bin/env python
if __name__ == '__main__':
try:
numA=input("请输入数字A: ")
Oper=input("请选择运算符(+|-|*|/): ")
numB=input("请输入数字B: ")
def add(x,y):
return float(x)+float(y)
def subtract(x,y):
return float(x)-float(y)
def multiply(x,y):
return float(x)*float(y)
def divide(x,y):
if(y):
return float(x)/float(y)
else:
return "除数不能为0"
operator = {'+':add,'-':subtract,'*':multiply,'/':divide}
def f(x,oper,y):
return operator.get(oper)(x,y)
print("结果是 ",f(numA,Oper,numB))
except Exception:
print("您输入有错")
以上代码以下缺陷:
- 代码复用性差,如需复用要拷贝整个函数,效率低
- 扩展性差,如果需要增加其他的运算方法,比如平方,立方,需要改动源函数
第三版--业务的封装
#!/usr/bin/env python
def GetResult(numA,numB,Oper):
def add(x,y):
return x+y
def subtract(x,y):
return x-y
def multiply(x,y):
return x*y
def divide(x,y):
return x/y
operator = {'+':add,'-':subtract,'*':multiply,'/':divide}
return operator.get(Oper)(numA,numB)
if __name__ == '__main__':
try:
numA=input("请输入数字A: ")
Oper=input("请选择运算符(+|-|*|/): ")
numB=input("请输入数字B: ")
result = GetResult(float(numA),float(numB),Oper)
print("结果是: ",result)
except Exception:
print("您输入有错")
以上代码的优点:
- 初步实现了,函数的实现和调用分离,便于函数的复用
第四版--简单工厂模式
面向对象是把构成事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。
在计算器这个问题上,我们把加减乘除四则运算抽象出一种对象就是运算器,它包含两个私有的操作数和一个抽象方法GetResult。加减乘除四种运算符就继承这个运算器,并实现各自的GetResult方法。运算器有一个工厂OperationFactory,这个工厂用字典映射替换if-else的逻辑判断,提高效率。
其UML关系图如下:
#!/usr/bin/env python
import abc
import ast
class Operation:
def __init__(self):
self.__numberA=None
self.__numberB=None
@property
def numberA(self):
return self.__numberA
@numberA.setter
def numberA(self,value):
self.__numberA=value
@property
def numberB(self):
return self.__numberB
@numberB.setter
def numberB(self,value):
self.__numberB=value
@abc.abstractmethod
def GetResult(self):
pass
class OperationAdd(Operation):
def GetResult(self):
return self.numberA+self.numberB
class OperationSub(Operation):
def GetResult(self):
return self.numberA-self.numberB
class OperationMul(Operation):
def GetResult(self):
return self.numberA*self.numberB
class OperationDiv(Operation):
def GetResult(self):
if(numberB==0):
raise Exception ("除数不能为0")
return self.numberA/self.numberB
class OperationFactory:
def createOperate(oper):
operator = {'+':OperationAdd(),'-':OperationSub(),'*':OperationMul(),'/':OperationDiv()}
return operator.get(oper)
if __name__ == '__main__':
numA = ast.literal_eval(input("请输入数字A: "))
oper_sympol = input("请输入运算符(+,-,*,/): ")
oper = OperationFactory.createOperate(oper_sympol)
oper.numberA = numA
oper.numberB = ast.literal_eval(input("请输入数字B: "))
print(oper.GetResult())
上述简单工厂模式实现的计算器的优点:
- 封装性。只需要输入操作数和运算符,无需关心如何实现的,使用者一般也不会看到是如何实现的(使用者只会看到程序入口即if __name__ == '__main__':包含的内容)。
- 易扩展。如果要实现平方或其他运算,你可以像OperationAdd方法类似,独立增加一个运算类,然后在OperationFactory里的operator字典增加一个键值对。
- 封闭性比如工厂模式和抽象工厂模式高。因为在扩展其他运算类的时候,需要改动工厂方法。而工厂方法里面暴露了其他方法的一些信息。