python-design-pattern

  1. 参考
  2. 注册表(Registry)

设计模式,学习 软件工程 的一些规范和前人的总结

参考

注册表(Registry)

我们写代码的时候经常写出 大量的 if-elif 不利于后续维护性的代码

扩展性很差,修改代码会破坏结构,耦合度太高了,比如下面的代码

def cmd_start():
    print("Starting service...")

def cmd_stop():
    print("Stopping service...")

def cmd_restart():
    print("Restarting service...")


def handle_command(cmd: str):
    """根据命令字符串选择对应函数执行(非注册表版)"""
    if cmd == "start":
        cmd_start()
    elif cmd == "stop":
        cmd_stop()
    elif cmd == "restart":
        cmd_restart()
    else:
        print("Unknown command:", cmd)


if __name__ == "__main__":
    handle_command("start")
    handle_command("stop")
    handle_command("restart")
    handle_command("status")  # 未知命令

聪明的你很快就想到了使用 Dict 存放,采用 Key-Val 的方式,这样就能最低限度的侵入性

注册表模式的核心思想是:把某一类对象统一注册到一个中心容器中,通过字符串或键来访问它们,而不是硬编码依赖。

def cmd_start():
    print("Starting service...")

def cmd_stop():
    print("Stopping service...")

def cmd_restart():
    print("Restarting service...")


FUNC_MAP: dict[str, callable] = {
    "start": cmd_start,
    "restart": cmd_restart,
    "stop": cmd_stop
}

def handle_command(cmd: str):
    """根据命令字符串选择对应函数执行(非注册表版)"""
    for key, func in FUNC_MAP.items():
        if cmd == key:
            func()
            return
    print("Unknown command:", cmd)

if __name__ == "__main__":
    handle_command("start")
    handle_command("stop")
    handle_command("restart")
    handle_command("status")  # 未知命令

我们更进一步,使用 python装饰器 的特性,就得出了注册表(Registry)

# 1. 定义一个全局注册表
COMMAND_REGISTRY: dict[str, callable] = {}


# 2. 定义一个装饰器,用来把函数注册进去
def register_command(name: str):
    def decorator(func):
        COMMAND_REGISTRY[name] = func
        return func  # 返回原函数,便于正常调用/测试
    return decorator


# 3. 各个命令通过装饰器注册自己
@register_command("start")
def cmd_start():
    print("Starting service...")


@register_command("stop")
def cmd_stop():
    print("Stopping service...")


@register_command("restart")
def cmd_restart():
    print("Restarting service...")


# 4. 统一的命令处理入口
def handle_command(cmd: str):
    func = COMMAND_REGISTRY.get(cmd)
    if func is None:
        print("Unknown command:", cmd)
    else:
        func()


if __name__ == "__main__":
    handle_command("start")
    handle_command("stop")
    handle_command("restart")
    handle_command("status")  # 未知命令

各大出名的开源框架,比如 fastapi的路由注册,pytorch的模型注册,插件注册都使用的是 Registry设计模式;这种设计模式非常非常适合写 plug-in

github