今日のトピックは「ストラテジーパターンとステートパターン」です。ストラテジーパターンとステートパターンは、いずれもオブジェクトの振る舞いを動的に変更するためのデザインパターンですが、それぞれ異なる目的とアプローチを持ちます。ストラテジーパターンは、アルゴリズムをカプセル化し、実行時に選択できるようにするために使用され、ステートパターンはオブジェクトの内部状態に応じてその振る舞いを変更するために使用されます。
目次
基本概念の説明
ストラテジーパターン (Strategy Pattern)
ストラテジーパターンは、異なるアルゴリズムを定義し、それらをクライアントから切り離してカプセル化するためのデザインパターンです。これにより、アルゴリズムの変更が容易になり、実行時に動的にアルゴリズムを選択することが可能になります。
ステートパターン (State Pattern)
ステートパターンは、オブジェクトの内部状態に基づいて、その振る舞いを動的に変更するためのデザインパターンです。このパターンを使用することで、状態ごとの複雑な条件分岐を避け、コードをシンプルで管理しやすいものにできます。
各言語でのサンプルコード
Python
ストラテジーパターン
from abc import ABC, abstractmethod
class Strategy(ABC):
@abstractmethod
def execute(self, a, b):
pass
class AddStrategy(Strategy):
def execute(self, a, b):
return a + b
class SubtractStrategy(Strategy):
def execute(self, a, b):
return a - b
class Context:
def __init__(self, strategy: Strategy):
self._strategy = strategy
def set_strategy(self, strategy: Strategy):
self._strategy = strategy
def execute_strategy(self, a, b):
return self._strategy.execute(a, b)
# 使用例
context = Context(AddStrategy())
print(context.execute_strategy(5, 3)) # 8
context.set_strategy(SubtractStrategy())
print(context.execute_strategy(5, 3)) # 2
ステートパターン
from abc import ABC, abstractmethod
class State(ABC):
@abstractmethod
def handle(self, context):
pass
class ConcreteStateA(State):
def handle(self, context):
print("State A: Handling request")
context.set_state(ConcreteStateB())
class ConcreteStateB(State):
def handle(self, context):
print("State B: Handling request")
context.set_state(ConcreteStateA())
class Context:
def __init__(self, state: State):
self._state = state
def set_state(self, state: State):
self._state = state
def request(self):
self._state.handle(self)
# 使用例
context = Context(ConcreteStateA())
context.request() # State A: Handling request
context.request() # State B: Handling request
C#
ストラテジーパターン
using System;
public interface IStrategy {
int Execute(int a, int b);
}
public class AddStrategy : IStrategy {
public int Execute(int a, int b) {
return a + b;
}
}
public class SubtractStrategy : IStrategy {
public int Execute(int a, int b) {
return a - b;
}
}
public class Context {
private IStrategy _strategy;
public Context(IStrategy strategy) {
_strategy = strategy;
}
public void SetStrategy(IStrategy strategy) {
_strategy = strategy;
}
public int ExecuteStrategy(int a, int b) {
return _strategy.Execute(a, b);
}
}
// 使用例
class Program {
static void Main() {
Context context = new Context(new AddStrategy());
Console.WriteLine(context.ExecuteStrategy(5, 3)); // 8
context.SetStrategy(new SubtractStrategy());
Console.WriteLine(context.ExecuteStrategy(5, 3)); // 2
}
}
ステートパターン
using System;
public interface IState {
void Handle(Context context);
}
public class ConcreteStateA : IState {
public void Handle(Context context) {
Console.WriteLine("State A: Handling request");
context.SetState(new ConcreteStateB());
}
}
public class ConcreteStateB : IState {
public void Handle(Context context) {
Console.WriteLine("State B: Handling request");
context.SetState(new ConcreteStateA());
}
}
public class Context {
private IState _state;
public Context(IState state) {
_state = state;
}
public void SetState(IState state) {
_state = state;
}
public void Request() {
_state.Handle(this);
}
}
// 使用例
class Program {
static void Main() {
Context context = new Context(new ConcreteStateA());
context.Request(); // State A: Handling request
context.Request(); // State B: Handling request
}
}
C++
ストラテジーパターン
#include <iostream>
class Strategy {
public:
virtual int execute(int a, int b) const = 0;
virtual ~Strategy() {}
};
class AddStrategy : public Strategy {
public:
int execute(int a, int b) const override {
return a + b;
}
};
class SubtractStrategy : public Strategy {
public:
int execute(int a, int b) const override {
return a - b;
}
};
class Context {
const Strategy* strategy;
public:
Context(const Strategy* strategy) : strategy(strategy) {}
void set_strategy(const Strategy* new_strategy) {
strategy = new_strategy;
}
int execute_strategy(int a, int b) const {
return strategy->execute(a, b);
}
};
// 使用例
int main() {
AddStrategy add;
SubtractStrategy subtract;
Context context(&add);
std::cout << context.execute_strategy(5, 3) << std::endl; // 8
context.set_strategy(&subtract);
std::cout << context.execute_strategy(5, 3) << std::endl; // 2
return 0;
}
ステートパターン
#include <iostream>
class Context;
class State {
public:
virtual void handle(Context* context) = 0;
virtual ~State() {}
};
class ConcreteStateA : public State {
public:
void handle(Context* context) override;
};
class ConcreteStateB : public State {
public:
void handle(Context* context) override;
};
class Context {
State* state;
public:
Context(State* state) : state(state) {}
void set_state(State* new_state) {
state = new_state;
}
void request() {
state->handle(this);
}
};
// 実装
void ConcreteStateA::handle(Context* context) {
std::cout << "State A: Handling request" << std::endl;
context->set_state(new ConcreteStateB());
}
void ConcreteStateB::handle(Context* context) {
std::cout << "State B: Handling request" << std::endl;
context->set_state(new ConcreteStateA());
}
// 使用例
int main() {
Context context(new ConcreteStateA());
context.request(); // State A: Handling request
context.request(); // State B: Handling request
return 0;
}
Java
ストラテジーパターン
interface Strategy {
int execute(int a, int b);
}
class AddStrategy implements Strategy {
public int execute(int a, int b) {
return a + b;
}
}
class SubtractStrategy implements Strategy {
public int execute(int a, int b) {
return a - b;
}
}
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int a, int b) {
return strategy.execute(a, b);
}
}
// 使用例
public class Main {
public static void main(String[] args) {
Context context = new Context(new AddStrategy());
System.out.println(context.executeStrategy(5, 3)); // 8
context.setStrategy(new SubtractStrategy());
System.out.println(context.executeStrategy(5, 3)); // 2
}
}
ステートパターン
interface State {
void handle(Context context);
}
class ConcreteStateA implements State {
public void handle(Context context) {
System.out.println("State A: Handling request");
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB implements State {
public void handle(Context context) {
System.out.println("State B: Handling request");
context.setState(new ConcreteStateA());
}
}
class Context {
private State state;
public Context(State state) {
this.state = state;
}
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}
// 使用例
public class Main {
public static void main(String[] args) {
Context context = new Context(new ConcreteStateA());
context.request(); // State A: Handling request
context.request(); // State B: Handling request
}
}
JavaScript
ストラテジーパターン
class Strategy {
execute(a, b) {
throw new Error("This method should be overridden!");
}
}
class AddStrategy extends Strategy {
execute(a, b) {
return a + b;
}
}
class SubtractStrategy extends Strategy {
execute(a, b) {
return a - b;
}
}
class Context {
constructor(strategy) {
this.strategy = strategy;
}
setStrategy(strategy) {
this.strategy = strategy;
}
executeStrategy(a, b) {
return this.strategy.execute(a, b);
}
}
// 使用例
const context = new Context(new AddStrategy());
console.log(context.executeStrategy(5, 3)); // 8
context.setStrategy(new SubtractStrategy());
console.log(context.executeStrategy(5, 3)); // 2
ステートパターン
class State {
handle(context) {
throw new Error("This method should be overridden!");
}
}
class ConcreteStateA extends State {
handle(context) {
console.log("State A: Handling request");
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB extends State {
handle(context) {
console.log("State B: Handling request");
context.setState(new ConcreteStateA());
}
}
class Context {
constructor(state) {
this.state = state;
}
setState(state) {
this.state = state;
}
request() {
this.state.handle(this);
}
}
// 使用例
const context = new Context(new ConcreteStateA());
context.request(); // State A: Handling request
context.request(); // State B: Handling request
各言語の解説
言語 | ストラテジーパターンの実装方法 | ステートパターンの実装方法 | 特徴 |
---|---|---|---|
Python | 抽象クラスと継承を使用してアルゴリズムをカプセル化 | 状態クラスを使用してオブジェクトの振る舞いを制御 | シンプルで柔軟、直感的に実装可能 |
C# | インターフェースとクラスを使用してアルゴリズムをカプセル化 | インターフェースとクラスを使用してオブジェクトの状態を管理 | 強力な型安全性と拡張性、オブジェクト指向の設計が容易 |
C++ | 仮想メソッドと継承を使用してアルゴリズムをカプセル化 | 状態クラスを使用してオブジェクトの振る舞いを制御 | 高速で効率的、特に低レベルプログラムで有効 |
Java | インターフェースとクラスを使用してアルゴリズムをカプセル化 | インターフェースとクラスを使用してオブジェクトの状態を管理 | 強力なオブジェクト指向機能と堅牢性、Javaの標準APIと統合が容易 |
JavaScript | クラスと継承を使用してアルゴリズムをカプセル化 | 状態クラスを使用してオブジェクトの振る舞いを制御 | 柔軟でシンプル、フロントエンドやNode.js環境に最適 |
まとめ
ストラテジーパターンは、異なるアルゴリズムをカプセル化し、動的に切り替えることができるため、コードの再利用性と柔軟性を向上させます。一方、ステートパターンは、オブジェクトの内部状態に基づいて振る舞いを変更するため、複雑な条件分岐を避け、コードを簡潔に保つことができます。次回は「テンプレートメソッドパターンとファクトリメソッドパターン」について学習しましょう。
コメント