クラスやオブジェクトを組み合わせて、より大きな構造を作るパターン群。多くは既存コードを変更せずに新しい振る舞いを 追加するために使われ、OCP の実現手段になる。
Adapter¶
インターフェースに互換性のないクラス同士を仲介し、既存コードを変更せずに接続するパターン。
外部ライブラリやレガシーAPIを自分のコードの期待するインターフェースに合わせたいときによく使う。
class LegacyPrinter:
def print_message(self, msg):
print(f"[legacy] {msg}")
class ModernPrinter:
def print(self, msg):
raise NotImplementedError
class PrinterAdapter(ModernPrinter):
def __init__(self, legacy: LegacyPrinter):
self.legacy = legacy
def print(self, msg):
self.legacy.print_message(msg)
printer: ModernPrinter = PrinterAdapter(LegacyPrinter())
printer.print("hello")[legacy] hello
Decorator¶
既存のオブジェクトを別のオブジェクトでラップし、動的に振る舞いを追加するパターン。継承によるサブクラスの組み合わせ爆発を避けられる。
Pythonの @decorator 構文は関数版のこのパターン。
class Coffee:
def cost(self):
return 300
class MilkDecorator:
def __init__(self, coffee):
self.coffee = coffee
def cost(self):
return self.coffee.cost() + 50
drink = MilkDecorator(Coffee())
print(drink.cost()) # 350350
Facade¶
複雑なサブシステム群に対して、単純化された統一インターフェースを提供するパターン。利用者はサブシステムの内部構造を 意識せずに済むようになる。
class CPU:
def start(self): print("CPU start")
class Memory:
def load(self): print("Memory load")
class Disk:
def read(self): print("Disk read")
class ComputerFacade:
def __init__(self):
self.cpu, self.memory, self.disk = CPU(), Memory(), Disk()
def start_computer(self):
self.cpu.start()
self.memory.load()
self.disk.read()
ComputerFacade().start_computer()CPU start
Memory load
Disk read
Composite¶
個々のオブジェクトとその集合を同じインターフェースで扱えるようにし、木構造(部分-全体階層)を統一的に扱うパターン。 ファイルシステムのファイル/ディレクトリ、UIコンポーネントツリーなどが典型例。
class FileSystemItem:
def size(self): raise NotImplementedError
class File(FileSystemItem):
def __init__(self, size):
self._size = size
def size(self):
return self._size
class Directory(FileSystemItem):
def __init__(self):
self.children = []
def add(self, item: FileSystemItem):
self.children.append(item)
def size(self):
return sum(child.size() for child in self.children)
root = Directory()
root.add(File(100))
sub = Directory()
sub.add(File(50))
root.add(sub)
print(root.size()) # 150150