Python基礎 オブジェクト指向3(Adapter) 構造に関するデザインパターン
| 登録日 | :2025/09/23 08:40 |
|---|---|
| カテゴリ | :Python基礎 |
Adapterとは
あるクラスのインターフェースを、そのクラスを利用する側が求める他のインターフェースへ変換するパターン。(API)
インターフェースに互換性のないクラス同士を組み合わせることができる。
構造に関するデザインパターン
Adapterの構成要素
-
Client
あるクラスの機能を「利用する」側のクラス -
Target
Clientが必要とする機能のAPIを定義するインターフェース -
Adapteeクラス(継承される元)
利用される側のクラス
Clientクラスと互換性ない。 -
Adapter
Targetを実装するクラス
Adapteeを継承する子クラス
TargetのAPIを実装して、Adapteeの機能をClientが利用できるようにする -
実装方法
- 継承をする
- 移譲する
可能であれば、2.移譲する方法を推奨する(SOLIDの原則を満たしやすい)
Adapterのメリット・デメリット
メリット
- 既存のクラス(Adaptee)を修正しないので再テストが不要になる
- 変換のためのコードをプログラムのビジネスロジックと分離できるので単一責任の原則に違反しない
- インターフェースを介してアダプタと連携するのでオープンクローズドの原則に違反しない
デメリット
- インターフェースやクラスが増えるので、小さなシステムなどではAdapteeを直接修正した方が良い場合もある
Adapterの使い所
既存のクラスを利用したが、そのインターフェースが利用したい側のコードと互換性がない場合
過去に十分テストされて実績のあるクラスに手を加えずに再利用したい場合
Adapteeのソースコードが手に入らない場合
Adapterの適用例
JSONデータをCSVに変換する例(継承を利用した実装)
Adapterの実装方法1(継承する)
サンプルコード
from abc import ABCMeta, abstractmethod
from typing import List, Dict
class Target(metaclass=ABCMeta):
@abstractmethod
def get_csv_data(self) -> str:
pass
class NewLibrary(object):
@staticmethod
def get_json_data() -> List[Dict[str, str]]:
return [
{
"data1": "Json_data_A",
"data2": "Json_data_B",
},
{
"data1": "Json_data_C",
"data2": "Json_data_D",
},
]
class JsonToCsvAdapter(NewLibrary, Target):
def get_csv_data(self) -> str:
json_data = self.get_json_data()
header = ",".join(list(json_data[0].keys())) + "\n"
body = "\n".join([",".join(list(d.values()))for d in json_data])
return header + body
if __name__ == '__main__':
adaptee = NewLibrary()
print("=== Adaptee data")
print(adaptee.get_json_data())
print("")
adapter = JsonToCsvAdapter()
print("=== Adapter converted data")
print(adapter.get_csv_data())
Adapterの実装方法2(権限委譲する)
委譲を使うことを推奨
サンプルコード
from abc import ABCMeta, abstractmethod
from typing import List, Dict
class Target(metaclass=ABCMeta):
@abstractmethod
def get_csv_data(self) -> str:
pass
class NewLibrary(object):
@staticmethod
def get_json_data() -> List[Dict[str, str]]:
return [
{
"data1": "Json_data_A",
"data2": "Json_data_B",
},
{
"data1": "Json_data_C",
"data2": "Json_data_D",
},
]
class JsonToCsvAdapter(Target):
def __init__(self, _adaptee: NewLibrary):
self.__adaptee = _adaptee
def get_csv_data(self) -> str:
json_data = self.__adaptee.get_json_data()
header = ",".join(list(json_data[0].keys())) + "\n"
body = "\n".join([",".join(list(d.values()))for d in json_data])
return header + body
if __name__ == '__main__':
adaptee = NewLibrary()
print("=== Adaptee data")
print(adaptee.get_json_data())
print("")
adapter = JsonToCsvAdapter(adaptee)
print("=== Adapter converted data")
print(adapter.get_csv_data())