概要
Registryパターンはシンプルで便利なパターン。あるクラスのすべてのサブクラスの記録(レジストリ)を管理することができる。これは、コードベース内のすべてのサブクラスの動作を管理、操作、または動的に更新するのに役立つ。すべてのPythonクラスは’type’メタクラスのインスタンスのため、このパターンを実装する非常に直感的な方法は、’type’のサブクラスを作成し、それを子クラスが登録されるベースクラスのメタクラスとして使用することだ。
以下の実装例では、「ErrorMeta」は「BaseError」とそのすべての子のメタクラスとして機能する。この仮想的なコードベースにおけるすべてのエラー(Exception)は ‘BaseError’ のサブクラスになると仮定する。また、このようなエラーはすべて意味のある「コード」を持つと仮定し、それをclass属性として設定する。メタクラスの’registry’属性は、’BaseError’のすべてのサブクラスの辞書を保持し、そのサブクラスのエラーコードをキーとする。
実装例
ErrorMetaクラスは、BaseErrorとそのサブクラスのメタクラスとして機能する。レジストリを単純な辞書として実装しているが、ユースケースに応じて変更することができる。例えば、登録されたクラスの継承関係をマッピングしたツリーやグラフとしてレジストリを実装することも有効。
デフォルトでは、__metaclass__は常に’type’であり、これをErrorMetaにオーバーライドすることで、このクラスとそのすべてのサブクラスがErrorMeta.__new__を呼び出し、結果的にレジストリに追加されることを保証する。
class ErrorMeta(type):
registry = {}
def __new__(cls, *args, **kwargs):
new_error_type = type.__new__(cls, *args, **kwargs)
# この例では、エラーコードがタイプを特定するためのキーとして機能する
cls.registry[new_error_type.__name__] = new_error_type
return new_error_type
class BaseError(Exception, metaclass=ErrorMeta):
code = 999
if __name__ == "__main__":
print(ErrorMeta.registry)
class ClientError(BaseError):
code = 400
class ServerError(BaseError):
code = 500
print(ErrorMeta.registry)