デザインパターン#

分類

説明

代表例 🧩

生成に関するパターン

オブジェクトの生成方法に関するパターン

Singleton, Factory Method, Builder, Prototype

構造に関するパターン

オブジェクトやクラスの構造(組み立て方)に関するパターン

Adapter, Decorator, Composite, Facade

振る舞いに関するパターン

オブジェクト間のやり取り・責務の分配方法に関するパターン

Observer, Strategy, State, Command, Iterator

Dependency Injection (依存性注入)#

依存関係を外部から注入するパターン

✅ メリット

  1. テストしやすい:モック(模擬オブジェクト)を渡せる

  2. 柔軟性が高い:実装を変えても呼び出し側は影響を受けない

  3. 再利用性が高い:同じクラスを異なる依存関係で再利用可能

EngineとCarというオブジェクトがあるとする。

DIをしない場合は依存性を外部から変更できない状態。

class Engine:
    def start(self):
        print("Engine started")

# DIなし:CarがEngineを自分で作る(依存が固定されている)
class Car:
    def __init__(self):
        self.engine = Engine()

    def run(self):
        self.engine.start()

DIを行う場合、例えばconstructorにengineを渡したりする

# DIあり:Engineを外部から渡す(柔軟に差し替えられる)
class Car:
    def __init__(self, engine: Engine):
        self.engine = engine

    def run(self):
        self.engine.start()

# 実行
engine = Engine()
car = Car(engine)  # Engineを注入
car.run()

DIの方法

(1) constructor injection

car = Car(engine)

(2) setter injection

car.set_engine(engine)

Singleton(シングルトン)#

インスタンスが1つしか存在しないようにする。インスタンスをグローバル変数のように扱う。

from datetime import datetime

class Singleton:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

class MyClass(Singleton):
    def __init__(self, value):
        self.value = value

m1 = MyClass("first")
print(f"{m1.value=}")

# m2を変えるとm1も変わる
m2 = MyClass("second")
print(f"{m1.value=}, {m2.value=}")
m1.value='first'
m1.value='second', m2.value='second'

Factory Method#

オブジェクトの生成処理をサブクラスに任せる(newを隠す)

class Animal:
    def speak(self): pass

class Dog(Animal):
    def speak(self): return "Woof!"

class Cat(Animal):
    def speak(self): return "Meow!"


def animal_factory(kind: str) -> Animal:
    if kind == "dog":
        return Dog()
    elif kind == "cat":
        return Cat()

a = animal_factory("dog")
print(a.speak())
Woof!

Observer#

状態が変わったら通知(イベントリスナー)

class Subject:
    def __init__(self):
        self.observers = []

    def attach(self, observer):
        self.observers.append(observer)

    def notify(self, msg):
        for ob in self.observers:
            ob.update(msg)

class Observer:
    def update(self, msg):
        print("Got:", msg)

s = Subject()
s.attach(Observer())
s.notify("Update available")
Got: Update available

Strategy#

アルゴリズムを切り替えられるようにする

class Strategy:
    def execute(self, data):
        pass

class Add(Strategy):
    def execute(self, data):
        return sum(data)

class Multiply(Strategy):
    def execute(self, data):
        result = 1
        for x in data: result *= x
        return result

def run(strategy: Strategy, data):
    return strategy.execute(data)

print(run(Add(), [1, 2, 3]))
print(run(Multiply(), [1, 2, 3]))
6
6