文章目录
前言
GOF设计模式分三大类:
- 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。
- 结构型模式:关注类和对象之间的组合,包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。
- 行为型模式:关注对象之间的交互,包括职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。
一、策略模式
策略模式(Strategy Pattern)
-
定义:定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。
-
解决问题:如何在不修改现有代码的前提下更换一种算法?
-
使用场景:
- 一个系统需要动态地在几种算法中选择一种。
- 一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重条件选择语句来实现。
- 不希望客户端知道复杂的、与算法相关的数据结构。
-
组成:
- Context(环境类):环境类是使用算法的角色,它在解决某个问题(即实现某个方法)时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略。
- Strategy(抽象策略类):它为所支持的算法声明了抽象方法,是所有策略类的父类。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。
- ConcreteStrategy(具体策略类):它实现了在抽象策略类中声明的算法。在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理。
-
补充说明:
- 在策略模式中,可以定义一些独立的类来封装不同的算法,每个类封装一种具体的算法。
- 策略模式的主要目的是将算法的定义与使用分开,也就是将算法的行为和环境分开。
- 环境类是需要使用算法的类。
- 策略模式提供了一种可插入式(Pluggable)算法的实现方案。
- 策略模式用于算法的自由切换和扩展,它是应用较为广泛的设计模式之一。
-
优点:
- 策略模式提供了对开闭原则的完美支持。
- 策略模式提供了管理相关的算法族的办法。
- 策略模式提供了一种可以替换继承关系的办法。
- 使用策略模式可以避免多重条件选择语句。
- 策略模式提供了一种算法的复用机制。由于将算法单独提取出来封装在策略类中,因此不同的环境类可以方便地复用这些策略类。
-
缺点:
- 无法同时在客户端使用多个策略类。
- 客户端必须理解这些算法的区别,以便适时选择恰当的算法。

二、策略模式示例
使用策略模式设计电影院打折方案
- 系统中需要为不同类型的用户提供不同的电影票打折方式,具体打折方案如下:
- (1)学生凭学生证可享受票价8折优惠。
- (2)年龄在10周岁及以下的儿童可享受每张票减免10元的优惠(原始票价需大于或等于20元)。
- (3)影院VIP用户除享受票价半价优惠外还可进行积分,积分累积到一定额度可换取电影院赠送的礼品。
- 该系统在将来可能还要根据需要引入新的打折方式。
- MovieTicket充当环境类角色,Discount充当抽象策略角色,StudentDiscount、ChildrenDiscount和VIPDiscount充当具体策略角色。
python
"""策略模式"""
### 抽象策略
class Discount:
"""折扣"""
def calculate(self, price: float) -> float:
raise NotImplementedError
### 具体策略
class StudentDiscount(Discount):
"""学生票折扣"""
def calculate(self, price):
print("学生票:", end="")
return price * 0.8
class ChildrenDiscount(Discount):
"""儿童票折扣"""
def calculate(self, price):
print("儿童票:", end="")
if price > 20:
return price - 10
else:
return price
class VIPDiscount(Discount):
"""VIP票折扣"""
def calculate(self, price):
print("VIP票:", end="")
print("增加积分!", end="")
return price * 0.5
### 环境类
class MovieTicket:
"""电影票"""
def __init__(self, price: float = None, discount: Discount = None):
self.price = price
self.discount = discount
def get_price(self) -> float:
return self.discount.calculate(self.price)
- 具体策略类的类名存储在配置文件strategy_conf.json
json
{
"class_name": "StudentDiscount"
}
- 使用工具类
JsonUtil
来读取配置文件
python
# 模块 utils.py
from pathlib import Path
import json
class JsonUtil:
@staticmethod
def get_value(key: str = "class_name", conf_file="config.json"):
"""读取配置文件,返回配置文件中的配置"""
path = Path(conf_file)
contents = path.read_text(encoding="utf-8")
conf = json.loads(contents)
return conf.get(key, None)
- 客户端代码
python
"""策略模式:客户端代码"""
from utils import JsonUtil
from strategy import MovieTicket, Discount
if __name__ == "__main__":
# 读取配置文件,获取具体策略类名,生成具体策略对象
class_name = JsonUtil.get_value(conf_file="strategy_conf.json")
if class_name is None:
raise ValueError
discount: Discount = getattr(__import__("strategy"), class_name)()
original_price = 100
mt = MovieTicket(original_price, discount)
print(f"原价 {original_price},打折后 {mt.get_price()}")
- 输出结果
sh
学生票:原价 100,打折后 80.0
您正在阅读的是《设计模式Python版》专栏!关注不迷路~