PAYATHON 2026

如何在 Python 中用 Strategy Pattern 重构多重 if-elif?

数据小陈

可以用“字典注册表 + 独立解析器类”实现 Strategy Pattern:字典将格式名称映射到解析器类,DataProcessor 调用传入的解析器。新增格式时,添加解析器并更新注册表即可,无须修改 DataProcessor。

ABC 定义解析器必须实现的接口,字典负责选择具体实现,两者可以一起使用。

完整实现

示例沿用原代码返回提示字符串的行为,用来展示代码结构,不会真正解析 JSON、XML 或 CSV。原代码缺少必要的缩进,这里的缩进已调整为合法的 Python 缩进。

from abc import ABC, abstractmethod


class Parser(ABC):
    @abstractmethod
    def parse(self, data: str) -> str:
        pass


class JSONParser(Parser):
    def parse(self, data: str) -> str:
        return f"Parsing JSON: {data}"


class XMLParser(Parser):
    def parse(self, data: str) -> str:
        return f"Parsing XML: {data}"


class CSVParser(Parser):
    def parse(self, data: str) -> str:
        return f"Parsing CSV: {data}"


PARSER_CLASSES = {
    "json": JSONParser,
    "xml": XMLParser,
    "csv": CSVParser,
}


def create_parser(format_type: str) -> Parser:
    try:
        parser_class = PARSER_CLASSES[format_type]
    except KeyError:
        raise ValueError(
            f"Unsupported format: {format_type}"
        ) from None

    return parser_class()


class DataProcessor:
    def __init__(self, parser: Parser):
        self._parser = parser

    def process(self, data: str) -> str:
        return self._parser.parse(data)


processor = DataProcessor(create_parser("json"))
print(processor.process("{'key': 'value'}"))

输出为:

Parsing JSON: {'key': 'value'}

create_parser() 中的异常处理只包围字典查找,因此解析器构造函数内部抛出的 KeyError 不会被误报为“不支持的格式”。

为什么工厂中不再需要 if-elif?

原来的分支同时承担格式选择和解析工作。重构后,各个类负责具体解析逻辑,注册表负责格式选择:

"json" -> JSONParser
"xml"  -> XMLParser
"csv"  -> CSVParser

工厂查表并创建对象。DataProcessor 接收已经选好的策略,无须知道格式名称、注册表或具体解析器类。

调用方式也从原来的 process(format_type, data) 改为创建时选择格式、处理时传入数据。同一个 processor 可以继续处理多份使用相同解析策略的数据。

新增格式时修改哪里?

例如,需要增加一种自定义的逐行文本格式,可以新增解析器并注册:

class LinesParser(Parser):
    def parse(self, data: str) -> str:
        return f"Parsing lines: {data}"


PARSER_CLASSES["lines"] = LinesParser

processor = DataProcessor(create_parser("lines"))
print(processor.process("first\nsecond"))

DataProcessor 和 create_parser() 都不需要修改。注册代码应在使用该格式之前执行,通常可以集中放在应用初始化阶段。

支持新格式仍需要声明名称与解析器的对应关系。把配置集中在注册表中,可以避免每增加一种格式就修改处理类。

字典和 ABC 是否符合 Python 的惯用写法?

字典保存类或函数都是常见的 Python 写法,适合按名称选择行为的场景。Strategy Pattern 并不要求使用特定的工厂结构。

ABC 也不是必需的。只要传入的对象提供兼容的 parse() 方法,DataProcessor 就可以调用它,这属于鸭子类型。ABC 的好处是明确表达接口,并阻止没有实现抽象方法的子类被实例化。

不过,ABC 不会完整检查方法签名,也不会保证返回值类型正确;示例中的类型注解本身也不会执行运行时类型校验。如果项目规模较小,策略只是几个简单函数,也可以直接建立函数注册表,无须为了使用设计模式而增加类。

实际解析时需要注意什么?

  • 示例假设所有解析器都能无参数实例化。如果不同解析器需要不同配置,可以在注册表中保存工厂函数,由函数完成创建。
  • 注册表保存的是类,每次调用 create_parser() 都会创建新实例。若改为保存实例,需要考虑解析器是否携带可变状态,以及是否适合共享。
  • 当前示例只返回字符串。换成真实解析逻辑后,需要重新约定返回类型;JSON、XML 和 CSV 的解析结果未必具有相同结构。
  • 原示例中的 "{'key': 'value'}" 是一个 Python 字符串,其内容不是合法 JSON。若接入真正的 JSON 解析,应使用如 ' {"key": "value"} ' 这样的内容,或去掉两端空格写成 '{"key": "value"}'。

备注:内容仅供参考。