2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで実装するDecoratorパターン:機能を包み込む拡張可能な設計

Posted at

概要

Decorator(デコレーター)パターンは、
あるオブジェクトに対して、元のインターフェースを保ったまま、機能を段階的に追加する構造パターンである。

継承ではなく構成(composition)を用いることで、既存コードの修正を一切加えずに柔軟な機能拡張を可能にする
Pythonの文法におけるデコレーター構文(@)とは異なるが、設計思想としては共通している。


1. なぜDecoratorが必要か?

❌ 機能追加のために継承を繰り返す構造

class Coffee:
    def cost(self): return 300

class MilkCoffee(Coffee):
    def cost(self): return super().cost() + 50

→ 継承チェーンが増えるほど、柔軟性が低下し組み合わせの爆発が起こる


✅ 機能をラップして動的に積み重ねる

coffee = MilkDecorator(SugarDecorator(PlainCoffee()))
coffee.cost()  # → 拡張された合計

拡張の順序・有無を自由にコントロール可能に


2. 基本構造

✅ Component(共通インターフェース)

class Beverage:
    def cost(self):
        raise NotImplementedError

✅ ConcreteComponent(元のオブジェクト)

class PlainCoffee(Beverage):
    def cost(self):
        return 300

✅ Decorator(共通のラッパー構造)

class CoffeeDecorator(Beverage):
    def __init__(self, beverage: Beverage):
        self._beverage = beverage

✅ ConcreteDecorators(拡張ロジック)

class MilkDecorator(CoffeeDecorator):
    def cost(self):
        return self._beverage.cost() + 50

class SugarDecorator(CoffeeDecorator):
    def cost(self):
        return self._beverage.cost() + 30

✅ 使用例

coffee = PlainCoffee()
print(coffee.cost())  # 300

decorated = MilkDecorator(SugarDecorator(coffee))
print(decorated.cost())  # 300 + 30 + 50 = 380

3. Python的応用:関数デコレーターと構造パターンの融合

def logging_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"[LOG] 呼び出し: {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

@logging_decorator
def greet(name):
    print(f"Hello, {name}!")
greet("Alice")
# → [LOG] 呼び出し: greet
# → Hello, Alice!

関数ベースでもDecorator思想を自然に適用可能


4. 実務ユースケース

✅ UIコンポーネントへの装飾

→ ボタンに影・枠・アイコンなどを動的に追加する


✅ 認証・ロギング・トレースの挿入

→ メソッドやサービスに関心の横断的機能を非侵入的に注入


✅ ミドルウェアの設計(例:Flask / Django)

→ リクエスト処理をチェーン構造で構築する


✅ ストリーム処理(ファイル→暗号化→圧縮)

段階的な加工をDecoratorで表現


5. よくある誤用と対策

❌ 複数のデコレーターを順序依存で設計してしまう

→ ✅ 各Decoratorは順序に依存しない独立性を保つ設計を心がける


❌ Decoratorが元のインターフェースを壊してしまう

→ ✅ Decorator元のメソッドと引数を忠実に模倣すべき


❌ Decoratorのネストが可読性を損なう

→ ✅ 構成順に名前を付けて変数に代入し、明示的なスタック構造に


結語

Decoratorパターンとは、“機能を段階的に包み込みながら拡張する柔構造設計”である。

  • 継承に頼らず、構成とラップによって機能を動的に追加・削除できる
  • 主処理と副作用(ログ・認証・スタイル等)を分離可能にし、再利用性を高める
  • Pythonでは関数・クラスの両レベルで、デコレーターの思想を直感的に実装可能

Pythonicとは、“動的で柔軟な拡張性を最小限の変更で実現する”ことであり、
Decoratorパターンはその重ねられた機能美を、洗練されたレイヤーとしてコードに織り込む技法である。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?