🧩 Strategy パターン
✅ 設計意図
- 条件ごとに異なる処理を「戦略(Strategy)」として分離
- どの戦略を使うかは外部から渡すことで切り替え可能
✅ 適用理由
- 分岐ロジックをオブジェクト単位に分けてテスト・追加が容易
- アルゴリズムの差し替えが求められるシステムに最適
✅ 向いているシーン
- アルゴリズムや処理ロジックを動的に切り替えたい
- 「これは A パターン」「これは B パターン」と明確な分類ができる場合
✅ コード例
- TypeScript
- PHP
- Python
// Strategy インターフェース
interface DiscountStrategy {
calculate(basePrice: number): number;
}
// ConcreteStrategy: 学生割引
class StudentDiscount implements DiscountStrategy {
calculate(basePrice: number): number {
return basePrice * 0.8;
}
}
// ConcreteStrategy: 会員割引
class MemberDiscount implements DiscountStrategy {
calculate(basePrice: number): number {
return basePrice * 0.9;
}
}
// ConcreteStrategy: VIP割引
class VIPDiscount implements DiscountStrategy {
calculate(basePrice: number): number {
return basePrice * 0.7;
}
}
// ConcreteStrategy: 割引なし
class NoDiscount implements DiscountStrategy {
calculate(basePrice: number): number {
return basePrice;
}
}
// Context クラス
class PriceCalculator {
constructor(private discountStrategy: DiscountStrategy) {}
calculatePrice(basePrice: number): number {
return this.discountStrategy.calculate(basePrice);
}
}
// 利用例
const basePrice = 1000;
const studentCalculator = new PriceCalculator(new StudentDiscount());
console.log(studentCalculator.calculatePrice(basePrice)); // 800
const memberCalculator = new PriceCalculator(new MemberDiscount());
console.log(memberCalculator.calculatePrice(basePrice)); // 900
const vipCalculator = new PriceCalculator(new VIPDiscount());
console.log(vipCalculator.calculatePrice(basePrice)); // 700
const regularCalculator = new PriceCalculator(new NoDiscount());
console.log(regularCalculator.calculatePrice(basePrice)); // 1000
<?php
// Strategy インターフェース
interface DiscountStrategy {
public function calculate(float $basePrice): float;
}
// ConcreteStrategy: 学生割引
class StudentDiscount implements DiscountStrategy {
public function calculate(float $basePrice): float {
return $basePrice * 0.8;
}
}
// ConcreteStrategy: 会員割引
class MemberDiscount implements DiscountStrategy {
public function calculate(float $basePrice): float {
return $basePrice * 0.9;
}
}
// ConcreteStrategy: VIP割引
class VIPDiscount implements DiscountStrategy {
public function calculate(float $basePrice): float {
return $basePrice * 0.7;
}
}
// ConcreteStrategy: 割引なし
class NoDiscount implements DiscountStrategy {
public function calculate(float $basePrice): float {
return $basePrice;
}
}
// Context クラス
class PriceCalculator {
private DiscountStrategy $discountStrategy;
public function __construct(DiscountStrategy $discountStrategy) {
$this->discountStrategy = $discountStrategy;
}
public function calculatePrice(float $basePrice): float {
return $this->discountStrategy->calculate($basePrice);
}
}
// 利用例
$basePrice = 1000;
$studentCalculator = new PriceCalculator(new StudentDiscount());
echo $studentCalculator->calculatePrice($basePrice) . PHP_EOL; // 800
$memberCalculator = new PriceCalculator(new MemberDiscount());
echo $memberCalculator->calculatePrice($basePrice) . PHP_EOL; // 900
$vipCalculator = new PriceCalculator(new VIPDiscount());
echo $vipCalculator->calculatePrice($basePrice) . PHP_EOL; // 700
$regularCalculator = new PriceCalculator(new NoDiscount());
echo $regularCalculator->calculatePrice($basePrice) . PHP_EOL; // 1000
from abc import ABC, abstractmethod
# Strategy インターフェース
class DiscountStrategy(ABC):
@abstractmethod
def calculate(self, base_price: float) -> float:
pass
# ConcreteStrategy: 学生割引
class StudentDiscount(DiscountStrategy):
def calculate(self, base_price: float) -> float:
return base_price * 0.8
# ConcreteStrategy: 会員割引
class MemberDiscount(DiscountStrategy):
def calculate(self, base_price: float) -> float:
return base_price * 0.9
# ConcreteStrategy: VIP割引
class VIPDiscount(DiscountStrategy):
def calculate(self, base_price: float) -> float:
return base_price * 0.7
# ConcreteStrategy: 割引なし
class NoDiscount(DiscountStrategy):
def calculate(self, base_price: float) -> float:
return base_price
# Context クラス
class PriceCalculator:
def __init__(self, discount_strategy: DiscountStrategy):
self._discount_strategy = discount_strategy
def calculate_price(self, base_price: float) -> float:
return self._discount_strategy.calculate(base_price)
# 利用例
base_price = 1000
student_calculator = PriceCalculator(StudentDiscount())
print(student_calculator.calculate_price(base_price)) # 800
member_calculator = PriceCalculator(MemberDiscount())
print(member_calculator.calculate_price(base_price)) # 900
vip_calculator = PriceCalculator(VIPDiscount())
print(vip_calculator.calculate_price(base_price)) # 700
regular_calculator = PriceCalculator(NoDiscount())
print(regular_calculator.calculate_price(base_price)) # 1000
✅ 解説
このコードは Strategy
パターン を使用して、異なる割引ロジックを柔軟に切り替えられる設計を実現している。
Strategy
パターンは、アルゴリズムや処理をクラスとして分離し、動的に切り替え可能にするデザインパターン。
1. Strategy パターンの概要
- Strategy: 共通のインターフェースを定義し、異なるアルゴリズムを統一的に扱う
- このコードでは
DiscountStrategy
が該当
- このコードでは
- ConcreteStrategy: Strategy を実装し、具体的なアルゴリズムを提供する
- このコードでは
StudentDiscount
,MemberDiscount
,VIPDiscount
,NoDiscount
が該当
- このコードでは
- Context:
Strategy
を利用するクラスで、具体的なアルゴリズムを動的に切り替える- このコードでは
PriceCalculator
が該当
- このコードでは
2. 主なクラスとその役割
DiscountStrategy
- 割引計算の共通インターフェース
calculate(basePrice: number): number
メソッドを定義
StudentDiscount
,MemberDiscount
,VIPDiscount
,NoDiscount
DiscountStrategy
を実装した具体的な割引ロジック- 各クラスで異なる割引率を適用
PriceCalculator
Context
クラス- コンストラクタで
DiscountStrategy
を受け取り、calculatePrice
メソッドで割引後の価格を計算
3. UML クラス図
4. Strategy パターンの利点
- 柔軟性: 新しい割引ロジックを追加する場合も、
DiscountStrategy
を実装するだけで対応可能 - 単一責任の原則: 各割引ロジックが独立したクラスに分離されており、保守性が高い
- 動的な切り替え: 実行時に異なる割引ロジックを簡単に切り替え可能
この設計は、アルゴリズムの切り替えが必要な場面で非常に有効であり、コードの拡張性と保守性を向上させる。