Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

構造に関するパターン(Structural Patterns)

クラスやオブジェクトを組み合わせて、より大きな構造を作るパターン群。多くは既存コードを変更せずに新しい振る舞いを 追加するために使われ、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())  # 350
350

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())  # 150
150

参考