2
3

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で構築するTemplate Method Pattern:フレームワークとカスタマイズの境界設計

Posted at

概要

**Template Method Pattern(テンプレートメソッドパターン)**は、
処理の枠組み(フレームワーク)を固定し、可変部分をサブクラスに委ねる設計パターンである。

不変な処理の流れと、変更可能な処理のポイントを明確に分離し、
拡張性と秩序を同時に担保する構造をもたらす。

本稿では、Pythonの継承機構と抽象メソッドを活用した実装例とともに、
このパターンの真価が発揮されるユースケースを解説する。


1. なぜテンプレートメソッドか?

❌ サブクラスが全体の処理順序まで定義してしまう

class Report:
    def generate(self):
        self.fetch_data()
        self.format()
        self.export()

→ 各サブクラスで generate() を書き直すと 処理順序がばらばらになり品質低下


✅ テンプレートメソッドで「流れ」だけ親クラスに定義

from abc import ABC, abstractmethod

class ReportGenerator(ABC):
    def generate(self):
        data = self.fetch_data()
        formatted = self.format(data)
        self.export(formatted)

    @abstractmethod
    def fetch_data(self): ...
    
    @abstractmethod
    def format(self, data): ...
    
    @abstractmethod
    def export(self, content): ...

処理の「流れ」は固定され、可変ポイントだけを明示的に実装可能


2. 実装例:CSVとJSONのレポート生成

class CSVReport(ReportGenerator):
    def fetch_data(self):
        return [{"id": 1, "name": "Alice"}]

    def format(self, data):
        return ",".join(data[0].keys()) + "\n" + ",".join(map(str, data[0].values()))

    def export(self, content):
        print("Exporting CSV:\n" + content)
class JSONReport(ReportGenerator):
    def fetch_data(self):
        return {"id": 1, "name": "Bob"}

    def format(self, data):
        import json
        return json.dumps(data)

    def export(self, content):
        print("Exporting JSON:\n" + content)
report = JSONReport()
report.generate()

3. フックメソッドによる柔軟性の追加

class ReportGenerator(ABC):
    def generate(self):
        self.before()
        data = self.fetch_data()
        formatted = self.format(data)
        self.export(formatted)
        self.after()

    def before(self): pass
    def after(self): pass

before() / after()任意オーバーライド可能なフックポイントとして提供


4. 実務ユースケース

✅ テストフレームワークの構造化

class TestCase:
    def run(self):
        self.setup()
        self.execute()
        self.teardown()

    def setup(self): pass
    def execute(self): raise NotImplementedError
    def teardown(self): pass

→ ユーザーは execute() だけを実装すればよく、テストの流れは崩れない


✅ データパイプラインの統一的設計

class DataPipeline:
    def run(self):
        raw = self.extract()
        transformed = self.transform(raw)
        self.load(transformed)

    def extract(self): raise NotImplementedError
    def transform(self, data): raise NotImplementedError
    def load(self, data): raise NotImplementedError

5. よくある誤用と対策

❌ サブクラスがテンプレートメソッドを上書きする

→ ✅ generate() などテンプレートメソッドは 最終形として親に固定すべき
→ Pythonでは慣習的に # Do not override コメントを付けることもある


❌ インタフェースと実装が混在し拡張不能

→ ✅ ABC + abstractmethod によって 設計意図を明示的に表現


結語

Template Method Pattern は、処理手順の「骨格」は変えず、局所的な実装を柔軟に差し替える設計思想である。

  • サブクラスは「何をするか」に集中し、「いつ・どの順で行うか」は親が制御
  • ソフトウェアの振る舞いをテンプレートとして固定することで、秩序と自由を両立
  • フレームワーク、データ処理、テスト基盤など、あらゆるレイヤーで活用可能

Pythonicとは、“振る舞いをオープンに、構造を堅牢に”設計することであり、
Template Method はその哲学を、継承という仕組みで最も明確に表現する構造である。

2
3
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
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?