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パターン:アルゴリズムの骨格を保ちつつ柔軟に拡張する設計

Posted at

概要

Template Method(テンプレートメソッド)パターンは、
アルゴリズム全体の流れ(骨格)をスーパークラスで定義し、
その中の一部のステップをサブクラスで実装させることによって、
処理の順序を維持したまま柔軟な拡張を可能にする構造的パターン
である。

「変わる部分」と「変わらない部分」を明確に分離できることから、
継承ベースの拡張戦略において極めて重要なポジションを占める。


1. なぜTemplate Methodが必要か?

❌ サブクラスが全体の流れを再定義してしまう

class FileProcessor:
    def run(self):
        self.read()
        self.process()
        self.save()

→ 継承側が自由に run() を書き換えてしまうと、流れが崩壊し、共通化の意味を失う


✅ スーパークラスに処理フローを固定し、

サブクラスに差分のみの実装を委ねる

class AbstractProcessor:
    def run(self):
        self.read()
        self.process()
        self.save()

    def read(self): ...
    def process(self): ...
    def save(self): ...

処理の構造は保証しつつ、個別の処理のみを差し替えられる設計に


2. 基本構造

✅ スーパークラス(抽象テンプレート)

class AbstractReport:
    def generate(self):
        self.fetch_data()
        self.analyze()
        self.render()

    def fetch_data(self):
        raise NotImplementedError

    def analyze(self):
        raise NotImplementedError

    def render(self):
        print("Rendering report...")  # 共通処理

✅ サブクラスによる拡張

class SalesReport(AbstractReport):
    def fetch_data(self):
        print("Fetching sales data...")

    def analyze(self):
        print("Analyzing sales trends...")

class HRReport(AbstractReport):
    def fetch_data(self):
        print("Fetching employee data...")

    def analyze(self):
        print("Analyzing retention rates...")

✅ 使用例

report = SalesReport()
report.generate()

# Output:
# Fetching sales data...
# Analyzing sales trends...
# Rendering report...

3. Python的応用:フックメソッドの導入

class Template:
    def run(self):
        self.before()
        self.main()
        self.after()

    def before(self):
        pass  # 任意実装

    def main(self):
        raise NotImplementedError

    def after(self):
        pass  # 任意実装

オプション的に実装可能な「フックメソッド」で柔軟性を持たせる


4. 実務ユースケース

✅ ファイル処理パイプライン(読み込み→加工→保存)

read(), process(), save() を固定フローにして、サブクラスでフォーマットや処理内容を切り替え


✅ バッチ処理の雛形定義

→ 共通化された run() に対して、ステップごとの処理のみカスタマイズ可能に


✅ Webフレームワーク内のView構成(Django CBVなど)

→ HTTPメソッドごとの処理フックをサブクラスで定義し、共通の構造を維持


✅ テストフレームワークでのライフサイクル管理

setup() → test() → teardown() のフローを保証しつつ、テストごとの処理を実装


5. よくある誤用と対策

❌ サブクラスがテンプレートメソッド(generate())自体をオーバーライド

→ ✅ スーパークラスのテンプレート構造は固定し、破壊的なオーバーライドを避ける


❌ 必須ステップを pass のままにして忘れる

→ ✅ NotImplementedError を明示的に仕込んで、未実装の検知性を高める


❌ 状態の共有が適切に設計されていない

→ ✅ 共通ステップと個別ステップが同じオブジェクトの状態を前提に設計されているかを確認


結語

Template Methodパターンとは、“アルゴリズムの構造とステップの自由度を両立させる”ための継承ベース構造設計である。

  • 全体の流れを固定しつつ、ステップ単位で差分実装を許容することで、拡張可能で堅牢な構造を維持
  • サブクラスに過度な責務を与えず、「型通りに拡張すればうまくいく」構造を保証
  • Pythonにおいても継承・オーバーライド・フックの活用により、テンプレートベースの再利用が直感的に実現可能

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?