设计模式-注册模式
软件架构设计中,一段代码太多的if-else分支会被认为是不好维护的,比如在某些场景下我们希望通过一个字符串来控制调用具体哪个方法
Python中,注册 通常是指将函数或对象与一个名称进行关联,以便在需要时能够方便地访问它们。
这种模式通常用于插件系统、事件处理和可扩展的应用程序中
结构型模式(Structural Patterns)--Registry 注册
注册中心(Registry Center)和注册对象(Registered Objects)。
注册中心负责存储和管理对象的引用,而注册对象则是需要注册到中心的对象实例
###常见问题
服务未正确注册 服务重复注册 服务注销失 >>> 单元测试 日志记录
服务注入攻击 服务泄露 服务伪装 >>> 服务验证 加密通信 访问控制
应用
动态加载和卸载组件
插件系统是注册模式的另一个高级应用
定义插件接口:首先,我们定义一个插件接口,用于规范插件的行为
创建 插件实例:接着,我们创建插件实例,实现插件接口
注册 插件:然后,我们将插件实例注册到注册中心
执行 插件:最后,我们可以通过注册中心执行插件
开发者控制,也可以是某些库或框架自动完成
对函数实现了注册器机制 对类实现注册器
知识点: 字典和函数 --> 闭包和装饰器 --> Registry 注册器 手动修改register这个字典 --> 自动修改register这个字典
Python 引入注册器机制保证了这个字典可以自动维护,增加或删除新的函数或类时,不需要手动去修改字典。
@decorator 是用来应用装饰器的语法糖,而不是直接调用装饰器函数
构建装饰器类时,需要将原本装饰器函数的部分实现于 __call__ 函数中
不想手动调用 register() 函数,可以在 Register 类中添加一个 __call__() 函数:
字典和函数
把这些指定的函数和类整合到一个字典,
可以用 函数名或类名作为字典的key,
也可用使用自定义的名字作为key, 对应的函数或类作为value
构建这样一个字典的过程就是注册,要手动修改register这个字典
功能: 根据输入条件的不同选择执行不同的函数,函数的输入参数一致
解决方式:
python通过字典选择调用的函数-定义一个字典,根据字典的值来进行执行函数
函数是一个对象,然后字典可以使用get方法来进行值的选取,或者使用[]
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
## action类
def get_upper(input_str):
return input_str.upper()
def get_lower(input_str):
return input_str.lower()
# 注册中心 注册action类 创建action对象
functions_dict = {
"lower": get_lower,
"upper": get_upper,
}
# 获取对应action类
def get_result(choice, input_str):
name_func = functions_dict[choice]
out_value = str(name_func(input_str))
print(out_value)
return out_value
if __name__ == "__main__":
input_str_a = "Study"
get_result("upper", input_str_a)
示例
注册模式解决if-else问题
Registry提供了字符串到函数或类的映射,这个映射会被整合到一个字典中,
开发者只要输入相应的字符串(为函数或类起的名字)和参数,就能获得一个函数或初始化好的类。
需要一个可以自动维护的字典,在我们定义一个函数或类的时候就自动把它整合到字典中
使用装饰器实现注册和注销的步骤
### 存储在 registry 字典中
registry = {}
def register(name):
def decorator(func):
registry[name] = func
return func
return decorator
### 简单注册:对象直接注册到注册中心,适用于对象数量较少且注册关系简单的情况
@register('plugin1')
def plugin1_func():
print("This is plugin 1.")
@register('plugin2')
def plugin2_func():
print("This is plugin 2.")
# 调用已注册的函数
registry['plugin1']() # 输出:This is plugin 1.
registry['plugin2']() # 输出:This is plugin 2.
# # 使用装饰器注册模块,比如一个函数
# 使用普通函数注册模块,比如一个类,先声明一个
注册中心的方式
###定义一个装饰器类Register,其中核心部分就是成员函数register,它作为一个装饰器函数:
class ServiceInfo:
def __init__(self, name, address):
self.name = name
self.address = address
self.is_alive = True
class Registry:
def __init__(self):
## 函数与给定的名称关联起来,并将其存储在 registry 字典中
self.services = {}
def register(self, service_info):
## service_info (type): 要注册的模块。通常是一个类或函数,但一般所有 Callable 类型都可以。
self.services[service_info.name] = service_info
def unregister(self, name):
if name in self.services:
del self.services[name]
## 提供查询接口:注册中心还需要提供一个接口,供外部查询特定服务实例的状态
def query(self, name):
return self.services.get(name)
class ServiceInstance:
def __init__(self, name, address):
*** = ServiceInfo(name, address)
def start(self):
registry.register(***)
def stop(self):
registry.unregister(***.name)
### ServiceInstance类:这个类代表一个服务实例,它在启动时调用start方法进行注册,在停止时调用stop方法进
注册
动态注册 是指在运行时动态地将模块或插件注册到系统中,
静态注册 则是在安装时将模块或插件注册到系统中
条件注册是指根据特定条件来决定是否注册某个模块或插件。分组注册是指将模块或插件分组注册,以便于管理和使用
PyTorch中算子注册
register_parameter 函数 用于注册模型参数,这些参数会在训练过程中进行优化
register_buffer 函数 用于注册模型的缓冲区。这些缓冲区通常是不需要进行梯度更新的张量,但它们需要与模型一起保存和加载,以便在推断时使用
CPU算子的注册入口在 build/aten/src/ATen/RegisterCPU.cpp 中,通过TORCH_LIBRARY_IMPL宏进行注册
哪些对象需要手动注册,哪些会自动注册
自动注册:
nn.Parameter: 任何 nn.Parameter 类型的属性会自动成为模型的参数。 model.parameters() 可以获得所有自动注册的参数
nn.Module 子类: 任何包含在 nn.Module 中的子模块(如 nn.Conv2d)会自动注册为模型的一部分。
需要使用 register_buffer 手动注册 buffers 使用 register_buffer 显式注册
触发
Trigger 触发
python中使用 监听 Listen 或者装饰器
triggers :触发器包含调度逻辑。每个作业都有自己的触发器,用于确定下一个任务何时运行
监听模式又名观察者模式
Observable是被观察者的抽象类,Observer是观察者的抽象类。
另外还有三个方法,分别用于添加和删除观察者,notifyObservers 用于内容或状态变化时通知所有的观察者
。因为Observable的notifyObservers会调用Observer的update方法,
所有观察者不需要关心被观察者的对象什么时候会发生变化,只要有变化就会自动调用update
from abc import ABCMeta, abstractmethod
# 引入ABCMeta 和 abstractmethod 来定义抽象类和抽象方法
# metaclass=ABCMeta : 使创建的类为抽象类
class Observer(metaclass=ABCMeta):
"""观察者的基类"""
@abstractmethod
def updata(self, observalbe, object):
pass
class Observable:
"""被观察者的基类"""
def __init__(self):
self.__observers = []
# 添加观察者
def addObserver(self, observer):
self.__observers.append(observer)
# 删除观察者
def removeObserver(self, observer):
self.__observers.remove(observer)
# 内容或状态变化时通知所有的观察者
def notifyObservers(self, object=0):
for o in self.__observers:
o.updata(self, object)
观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一种一对多的依赖关系,
监听模式根据侧重可以分为推模型和拉模型
让一个对象(称为“主题”或“被观察者”)的状态改变能够自动通知给依赖于它的多个对象(称为“观察者”)
推模型(Push Model 拉模型(Pull Model)
发布-订阅模式(Publish-Subscribe Pattern)
其他
模式(Visitor Pattern)是一种行为软件设计模式,它允许一个对象在不改变元素结构的情况下对一个对象的元素进行操作
尤其是在代码分析工具、 XML文档解析、编译器语法树遍历等领域。
参考
https://docs.python.org/zh-cn/3/library/optparse.html
https://docs.python.org/zh-cn/3/library/argparse.html
python argparse 源码阅读 https://game404.github.io/post/python/argparse/