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で学ぶデザインパターン入門:strategyパターン

2
Last updated at Posted at 2026-04-28

はじめに

はじめまして!この春からエンジニアとして働き始めた新入社員です。

現在、入社研修の一環としてPythonを使った課題に取り組んでいます。その中で デザインパターン を学ぶ機会があり、「せっかくなら記事にしてアウトプットしよう」と思い、この記事を書きました。
研修中の方や、Pythonを学び始めた方の参考にもなれば幸いです。


プログラミングを学び始めて少し経つと、こんな悩みが出てきませんか?

「コードは動くけど、なんかごちゃごちゃしている…」
「機能を追加するたびに、あちこち修正しないといけない…」
「他の人のコードが読めない…」

そんなときに助けてくれるのが デザインパターン です。
このシリーズでは、Pythonで知っておきたい5つのデザインパターンを、具体的なコード例とともに解説します。


デザインパターンとは

デザインパターンとは、ソフトウェア開発において よく遭遇する問題に対する、再利用可能な設計の「定石」 のことです。

1994年に出版された書籍 Design Patterns: Elements of Reusable Object-Oriented Software(通称「GoFの本」)で23のパターンが体系化され、現在も広く使われています。

デザインパターンを学ぶメリットは主に3つです。

メリット 説明
可読性の向上 パターン名で設計意図を共有できる
保守性の向上 変更に強いコードが書ける
再利用性の向上 似た問題に同じ解法を適用できる

このシリーズで紹介する5つのパターンは以下のとおりです。

パターン 一言で言うと 使いどころ
Strategy アルゴリズムを差し替える 処理の種類が増えそうな場合
Factory オブジェクト生成を一元管理 生成するクラスを切り替えたい場合
Observer 変化を自動通知 イベント駆動・疎結合にしたい場合
Template Method 骨格は共通、中身は任せる 同じ手順で一部だけ異なる処理がある場合
Decorator 機能を動的に追加 機能の組み合わせを柔軟にしたい場合

今回はこの5つのパターンのうちStrategyパターンについて書いていきたいと思います!

Strategy パターン(RPG 攻撃方法の切り替え)

どういったものか

「アルゴリズムをカプセル化して、動的に切り替えられる」 パターンです。

たとえばRPGゲームで、キャラクターが「剣」「魔法」「弓」など複数の攻撃方法を持つ場面を考えてみましょう。Strategyパターンを使わずに書くと、次のようになります。

class Character:
    def attack(self, attack_type: str, target: str) -> str:
        if attack_type == "sword":
            return f"剣で {target} を斬りつけた!"
        elif attack_type == "magic":
            return f"魔法で {target} に炎を放った!"
        elif attack_type == "bow":
            return f"弓で {target} を射抜いた!"
        # 攻撃方法が増えるたびに elif を追加し続けなければならない…

新しい攻撃方法(例:「投げナイフ」「サンダー魔法」)が増えるたびに、Character クラス自体を修正する必要があります。Strategyパターンを使うと、攻撃方法(戦略)をクラスとして分離し、キャラクターが持つ戦略を外から自由に差し替えられるようになります。

Character(キャラクター) ──uses──> AttackStrategy(攻撃方法)
                                          ├── SwordAttack(剣)
                                          ├── MagicAttack(魔法)
                                          └── BowAttack(弓)

どのように書くか

問題設定: RPGゲームで、キャラクターが「剣で攻撃」「魔法で攻撃」「弓で攻撃」など複数の攻撃方法を持つ場面を考えます。攻撃処理を if/else でキャラクタークラスに直接書いていくと、攻撃方法が増えるたびにクラスを修正しなければなりません。Strategyパターンを使うと、攻撃方法を「戦略」として分離し、キャラクターが持つ戦略を自由に差し替えられるようになります。

from abc import ABC, abstractmethod


# Strategy(戦略)の基底クラス
class AttackStrategy(ABC):
    @abstractmethod
    def attack(self, target: str) -> str:
        pass


# 具体的な戦略A:剣攻撃
class SwordAttack(AttackStrategy):
    def attack(self, target: str) -> str:
        return f"⚔️  剣で {target} を斬りつけた! ダメージ: 50"


# 具体的な戦略B:魔法攻撃
class MagicAttack(AttackStrategy):
    def attack(self, target: str) -> str:
        return f"✨ 魔法で {target} に炎を放った! ダメージ: 80"


# 具体的な戦略C:弓攻撃
class BowAttack(AttackStrategy):
    def attack(self, target: str) -> str:
        return f"🏹 弓で {target} を射抜いた! ダメージ: 35"


# Context(文脈):戦略を使う側
class Character:
    def __init__(self, name: str, strategy: AttackStrategy):
        self.name = name
        self._strategy = strategy

    def change_attack(self, strategy: AttackStrategy) -> None:
        """戦闘中でも攻撃方法を切り替えられる"""
        self._strategy = strategy

    def attack(self, target: str) -> str:
        return f"{self.name}{self._strategy.attack(target)}"


# 使い方

hero = Character("アレックス", SwordAttack())

print(hero.attack("スライム"))
# → 【アレックス】 ⚔️  剣で スライム を斬りつけた! ダメージ: 50

hero.change_attack(MagicAttack())

print(hero.attack("ドラゴン"))
# → 【アレックス】 ✨ 魔法で ドラゴン に炎を放った! ダメージ: 80

hero.change_attack(BowAttack())
print(hero.attack("ゴブリン"))
# → 【アレックス】 🏹 弓で ゴブリン を射抜いた! ダメージ: 35

新しい攻撃方法(例:「サンダー魔法」「投げナイフ」など)が増えても、AttackStrategy を継承した新しいクラスを追加するだけで対応できます。Character クラス本体を一切変更する必要がありません。

応用例

Strategyパターンは 「処理の種類が今後増えることが予想される」 場面で特に力を発揮します。

  • ECサイトの割引計算 — 通常価格・会員割引・セール割引など、割引ロジックをStrategyとして分離することで、新しい割引キャンペーンが追加されても既存コードに触れずに対応できます。
  • ファイルの出力形式 — CSV・JSON・Excelなど、出力形式ごとにStrategyを用意することで、形式の追加・変更が容易になります。
  • 認証方式の切り替え — パスワード認証・OAuth・SSO(シングルサインオン)など、認証方法を戦略として切り替えられるようにすることで、複数の認証プロバイダに対応しやすくなります。

まとめ

今回はデザインパターンの一つであるStrategyパターンについて書きました。
Strategyパターンについてまとめると以下のようになります。

項目 内容
目的 アルゴリズムをカプセル化し、実行時に切り替えられるようにする
解決する問題 if/elif の肥大化・処理追加のたびに既存クラスを修正する問題
メリット 新しい戦略の追加が既存コードを変えずにできる
デメリット クラス数が増える。戦略が1〜2種類しかないなら過剰設計になることも

✅ こういうときに使う

  • 同じ処理に「バリエーション」が複数ある
  • バリエーションが今後も増える予定がある
  • 実行時(ランタイム)に処理を切り替えたい

❌ 使わなくてよいとき

  • 処理のバリエーションが2種類以下で、今後も増える予定がない
  • 単純な if/else で十分に読みやすい場合

次回はFactoryパターンについて書こうと思います!

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?