Adapterパターン

本記事はGoFのデザインパターンの1つであるAdapterパターンについての解説と実際に実装した記事になります。 ソースコード

適応可能性

  • 既存のクラスを利用したいが、必要なインタフェースが既存のインタフェースと一致していない場合
  • 上記に加えて、既存のサブクラスを複数利用したい場合

解決策

必要なインタフェースを実装しつつ、既存のクラスにオペレーションの呼び出しを行うようなクラスを作成します。
これによってインタフェースや既存のクラスを変更する必要がなくなります。

方法として以下の2通り。

  • 多重結合(クラスに適応するAdapterパターン)
  • オブジェクトコンポジション(オブジェクトに適応するAdapterパターン)

UML図

コード例(クラスに適応するAdapterパターン)

クラスに適応するAdapterパターンには、多重結合を行うことで、既存のクラスの振る舞いをオーバーライドすることができます。

Targetクラスは print_messge と print_message_with_line の2つのインタフェースを提供するとします。


class Target:
    @abstractmethod
    def print_message(self):
        raise NotImpremetedError()

    @abstractmethod
    def print_message_with_line(self):
        raise NotImpremetedError()

Adapteeクラスは既に show_messgeとshow_message_with_lineを実装ずみとします。


class Adaptee:

    def __init__(self, message):
        self._message = message

    def show_message(self):
        print(self._message)

    def show_message_with_line(self):
        print('---- {} ----'.format(self._message))

TargetクラスのインタフェースでAdapteeクラスの処理を呼び出すには以下のようにAdapterクラスを2つのクラスを継承して作成します。


class Adapter(Adaptee, Target):

    def __init__(self, message):
        super().__init__(message)

    def print_message(self):
        self.show_message()

    def print_message_with_line(self):
        self.show_message_with_line()

target = Adapter('target message')
target.print_message()
target.print_message_with_line()

実行結果

target message
---- target message ----

コード例(オブジェクトに適応するAdapterパターン)

オブジェクトに適応するAdapterパターンは、オブジェクトコンポジションを使います。
こちらはAdapteeクラスの振る舞いをオーバーライドするのが難しいですが、Adapteeクラスやそのサブクラス、また複数のAdapteeクラスの機能を使うことができます。


class Adapter(Target):

    def __init__(self, message):
        self._adaptee = Adaptee(message)

    def print_message(self):
        self._adaptee.show_message()

    def print_message_with_line(self):
        self._adaptee.show_message_with_line()

注意点

クラスに適応するAdapterパターンは、Adapteeクラスの全てのサブクラスを適合したい場合は使うことができません。

また、Adapterクラスが行う物には、簡単なメソッド名の変更から全く異なる処理をサポートすることがまでが考えられますが、TargetクラスのインタフェースがどれだけAdapteeクラスのインタフェースに似ているかによりAdapterクラスの作業量が変わってきます。