[Python设计模式] 第1章 计算器——简单工厂模式

时间:2021-04-10 20:56:04

github地址:https://github.com/cheesezh/python_design_patterns

写在前面的话

"""
读书的时候上过《设计模式》这一门课,当时使用的教材是程杰老师的《大话设计模式》,使用的语言是C#,学过课程之后初期深感面向对象思想的伟大,但是很少应用到实际开发中。后来我接触了Python,现在工作中用到最多的也是Python,或许是因为Python的便利性,我写的很多脚本/程序都还是面向过程编程,缺少面向对象的思想在里边。因此,我打算重读程杰老师的《大话设计模式》并用Python进行实践。 """ by ZH奶酪——张贺

题目

用一种面向对象语言实现一个计算器控制台程序, 要求输入两个数和运算符号(+-*/), 得到结果.

基础版本

a = int(input("input a number:"))
b = str(input("input a operater(+ - * /):"))
c = int(input("input a number:")) if b == "+":
print(a+c)
elif b == "-":
print(a-c)
elif b == "*":
print(a*c)
else b == "/":
print(a/c)
input a number:16
input a operater(+ - * /):*
input a number:2
32

点评

  1. 变量命名不规范
  2. 无用的if条件判断太多
  3. 除法运算中未考虑第二个数字为0的情况

改进版本1.0——规范代码

number_a = int(input("input a number:"))
operator = str(input("input a operater(+ - * /):"))
number_b = int(input("input a number:")) if operator == "+":
print(number_a + number_b)
elif operator == "-":
print(number_a - number_b)
elif operator == "*":
print(number_a * number_b)
elif operator == "/":
if number_b != 0:
print(number_a / number_b)
else:
print("With operator '/', the second number can not be zero.")
else:
print("Wrong operator.")
input a number:12
input a operater(+ - * /):/
input a number:0
With operator '/', the second number can not be zero.

点评

  1. 没有使用面向对象的思想
  2. 只满足当前需求, 不易维护, 不易扩展, 不易复用, 不够灵活

为什么活字印刷术能位列四大发明?主要是其方法的思想。

  1. 文章改字方便, 可维护
  2. 一个字可以重复使用, 可复用
  3. 文章加字容易, 可扩展
  4. 文章改版只需移动活字, 灵活性好

复制?复用?

如果做一个带图形化界面的计算器,上边的代码需要再写一次。为了避免这样,需要将业务逻辑界面逻辑分开,降低耦合度。

改进版本2.0——利用封装解耦

class Operation():

    def __init__(self):
self.result = None def get_result(self, number_a, number_b, operator):
if operator == "+":
self.result = number_a + number_b
elif operator == "-":
self.result = number_a - number_b
elif operator == "*":
self.result = number_a * number_b
elif operator == "/":
if number_b != 0:
self.result = number_a / number_b
else:
print("With operator '/', the second number can not be zero.")
else:
print("Wrong operator.")
return self.result number_a = int(input("input a number:"))
operator = str(input("input a operater(+ - * /):"))
number_b = int(input("input a number:")) operation = Operation()
print(operation.get_result(number_a, number_b, operator))
input a number:12
input a operater(+ - * /):+
input a number:12
24

点评

  1. 仅仅用到了封装, 还没用到继承和多态。

紧耦合?松耦合?

如果要支持一个开根号运算,上边的代码需要改动包括加减乘除在内的get_result函数,应该将加减乘除运算分离, 修改其中一个不影响其他的几个。那么就需要定义一个Operator基类, 将get_result定义为虚函数,然后通过继承和多态,分别实现加减乘除四个子类,每个子类中定义虚函数的实现逻辑。

参考资料: Python中的多态与虚函数

改进版本3.0——简单工厂模式

from abc import ABCMeta, abstractmethod

class Operation():
__metaclass__ = ABCMeta def __init__(self):
self.result = None @abstractmethod
def get_result(self):
pass class AddOperation(Operation): def get_result(self, number_a, number_b):
self.result = number_a + number_b
return self.result class SubOperation(Operation): def get_result(self, number_a, number_b):
self.result = number_a - number_b
return self.result class MulOperation(Operation): def get_result(self, number_a, number_b):
self.result = number_a * number_b
return self.result class 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.result
self.result = number_a / number_b
return self.result

如何实例化?——简单工厂模式

现在加减乘除的实现逻辑已经进一步隔离,之后即使增加一个开根号运算符,也和加减乘除无关。那么如何去实例化这些类呢?可以用简单工厂模式

class OperationFactory():

    @classmethod
def create_operate(self, operator):
oper = None
if operator == "+":
oper = AddOperation()
elif operator == "-":
oper = SubOperation()
elif operator == "*":
oper = MulOperation()
elif operator == "/":
oper = DivOperation()
else:
print("Wrong operator.")
return oper

通过上边的简单工厂,输入运算符号,就可以实例化出对应的对象。下边是客户端的代码。

number_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:12
input a operater(+ - * /):-
input a number:12
0

点评

  1. 业务逻辑与界面逻辑隔离,不关心是控制台程序还是GUI程序
  2. 不同运算逻辑隔离,一个运算符的增删改操作不会影响其他运算
  3. 面向对象思想的封装,继承,多态都有所体现
  4. 易维护,易扩展,易复用