策略模式
定义一系列的算法,并将每一种算法封装起来,之后让它们之间可以相互替换使用。让算法独立于使用它的用户而自我变化是策略模式的主要功能。使用策略模式的系统提供不同算法实现的接口以及对算法的增删改查等功能的实现,最重要的是对各种算法实现封装,此类系统多是算法决策系统,由用户决定使用哪个算法。以我家楼下新开的火锅店的开业大酬宾优惠活动为应用场景,该活动有三种优惠方法:85折,满300减50,满500减100。
一、实现要求
1)需要一个总体类保存当前选择的策略,之后调用对应的具体算法。
2)可以随时改变当前策略。
3)每一种条件分支作为一个策略对应的算法单独实现。
二、实现步骤
1)创建策略接口
2)创建具体策略
3)创建上下文环境
4)展示消费者的消费实例
三、设计原则
1)“开-闭”原则
类可以扩展但不能修改,即开放拓展关闭修改,一个好的软件系统应该能在不修改代码的情况下扩展它的功能。实现该原则的关键是抽象化。
2)单一职责原则
一个类应该只有一个引起它变化的原因,即不能把变化原因各不相同的职责放在一起,因为不同的变化会影响到不相干的职责。
四、Demo
1)抽象策略类
class Strategy(object):
def get_cash(self, cash):
pass
2)具体策略类
# 具体策略类之85折子类
class Charge(Strategy):
def __init__(self, discount=0.85):
self.discount = discount
def get_cash(self, cash):
return cash * self.discount
# 具体策略类之满减子类一
class Reduction1(Strategy):
def __init__(self, cash_accepted=300, reduction=50):
self.cash_accepted = cash_accepted
self.reduction = reduction
def get_cash(self, cash):
if cash >= self.cash_accepted:
return cash - self.reduction
else:
print("您不满足该条件")
return cash
# 具体策略类之满减子类二
class Reduction2(Strategy):
def __init__(self, cash_accepted=500, reduction=100):
self.cash_accepted = cash_accepted
self.reduction = reduction
def get_cash(self, cash):
if cash >= self.cash_accepted:
return cash - self.reduction
else:
print("您不满足该条件")
return cash
3)上下文管理类
class Accept(object):
def __init__(self, cash_):
self.cash_ = cash_
def get_result(self, cash):
return self.cash_.get_cash(cash)
4)主函数
if __name__ == '__main__':
command = ''
while command != 'exit':
cashes = eval(input("原价: "))
types = {'85折': Accept(Charge()),
'满300减50': Accept(Reduction1()),
'满500减100': Accept(Reduction2()),}
model = input("选择折扣方式: 85折、满300减50、满500减100: ")
if model in types:
money = types[model]
print("需要支付: ", money.get_result(cashes))
else:
print("不存在的折扣方式")
command = input("按下回车键继续或输入exit退出:")
5)运行结果
五、UML类图
六、总结
1)上图可见抽象策略类Strategy定义了一个所需要方法的公共接口,下面三个具体策略类继承了抽象策略类,并定义了不同功能的get_cash(),即实现了多态。
2)最上面的上下文管理类,通过接收一个策略返回结果。当要更改策略时,只需在使用的时候传入不同的策略就可以,免去了修改类的麻烦,此为封装的体现。
3)通过以上处理提高了代码的内聚程度,降低了耦合程度。
七、范例代码地址
https://github.com/ArrogantW/Strategy-Pattern