大话设计模式--简单工厂模式(Python版本)

我的运行环境是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)

以上代码有三个问题:

  1. 问题一:变量命名不规范
  2. 问题二:判断分支,这样每次运算都要做三次无用的判断
  3. 问题三:重复代码多,性能和内存使用率低
  4. 问题四:复用性差,想复用就要重新拷贝代码
根据上述缺陷,做了如下改进:

  1. 使用规范变量名
  2. 将每种运算类型封装成函数
  3. 利用字典,取代if-else的分支判断,减少无用判断
  4. 增加了异常捕获机制,代码更加健壮

第二版--代码规范之后:

#!/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("您输入有错")

以上代码以下缺陷:

  1. 代码复用性差,如需复用要拷贝整个函数,效率低
  2. 扩展性差,如果需要增加其他的运算方法,比如平方,立方,需要改动源函数

第三版--业务的封装

#!/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("您输入有错")

以上代码的优点:

  1. 初步实现了,函数的实现和调用分离,便于函数的复用

第四版--简单工厂模式

面向对象是把构成事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。

在计算器这个问题上,我们把加减乘除四则运算抽象出一种对象就是运算器,它包含两个私有的操作数和一个抽象方法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())   

上述简单工厂模式实现的计算器的优点:

  1. 封装性。只需要输入操作数和运算符,无需关心如何实现的,使用者一般也不会看到是如何实现的(使用者只会看到程序入口即if __name__ == '__main__':包含的内容)。
  2. 易扩展。如果要实现平方或其他运算,你可以像OperationAdd方法类似,独立增加一个运算类,然后在OperationFactory里的operator字典增加一个键值对。
其缺点:

  1. 封闭性比如工厂模式和抽象工厂模式高。因为在扩展其他运算类的时候,需要改动工厂方法。而工厂方法里面暴露了其他方法的一些信息。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值