Python

Python デザインパターンを学ぶ Registryパターン

概要

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)