コマンドパターン
コマンドパターン(Command Pattern)はデータ駆動型のデザインパターンであり、振る舞い型パターンに属します。
コマンドパターンは、リクエストをオブジェクトとしてカプセル化し、異なるリクエストでクライアントをパラメータ化できるようにし、リクエストのキューイングやリクエストログの記録、および取り消し可能な操作のサポートを可能にします。
コマンドパターンの構造図:

はじめに
意図
リクエストをオブジェクトとしてカプセル化し、ユーザーが異なるリクエストを使用してクライアントをパラメータ化できるようにします。
主な解決問題
- ソフトウェアシステムにおけるリクエスト側と実行側の間の密結合の問題を解決します。特に、動作の記録、取り消し/やり直し、トランザクション処理などが必要なシナリオで有効です。
使用シーン
- 動作の記録、取り消し/やり直し、トランザクション処理が必要な場合は、コマンドパターンを使用してリクエスト側と実行側を疎結合にします。
実装方法
- コマンドインターフェースを定義する:すべてのコマンドが実装しなければならないインターフェース。
- 具体的なコマンドを作成する:コマンドインターフェースを実装する具体的なクラスで、リクエストを実行するメソッドを含みます。
- 呼び出し側:コマンドオブジェクトを保持し、コマンドの実行をトリガーします。
- 受信者:実際にコマンドを実行するオブジェクト。
重要なコード
- 受信者(Receiver):コマンドを実際に実行するオブジェクト。
- コマンド(Command):コマンドを実行するためのインターフェースを定義します。
- 呼び出し側(Invoker):コマンドオブジェクトを使用するエントリーポイント。
応用例
- Struts 1:ActionServletがInvokerとして機能し、モデル層のクラスが具体的なCommandとして機能します。
利点
- 結合度の低減:リクエスト側と実行側の間の結合度が低減されます。
- 拡張が容易:新しいコマンドをシステムに簡単に追加できます。
欠点
- コマンドクラスの過多:システムに具体的なコマンドクラスが多くなりすぎて、システムの複雑さが増す可能性があります。
使用上のアドバイス
- GUIでは、各ボタンやメニュー項目を1つのコマンドと見なすことができます。
- コマンドライン操作をシミュレートする必要があるシナリオでは、コマンドパターンを使用します。
注意事項
- システムがコマンドの取り消し(Undo)とやり直し(Redo)操作をサポートする必要がある場合、コマンドパターンは適切な選択です。
構造
主に以下のいくつかのコアな役割が関与します:
コマンド(Command):
- 操作を実行するためのインターフェースを定義し、通常は1つの
executeメソッドを含み、具体的な操作を呼び出すために使用されます。
- 操作を実行するためのインターフェースを定義し、通常は1つの
具体的なコマンド(ConcreteCommand):
- コマンドインターフェースを実装し、具体的な操作の実行を担当します。通常、受信者への参照を含み、受信者のメソッドを呼び出すことでリクエストの処理を完了します。
受信者(Receiver):
- リクエストに関連する操作の実行方法を知っており、実際にコマンドを実行するオブジェクトです。
呼び出し側/リクエスト側(Invoker):
- コマンドを送信するオブジェクトで、コマンドオブジェクトを保持し、コマンドの実行をトリガーできます。呼び出し側はリクエストを直接処理せず、リクエストをコマンドオブジェクトに渡すことで処理を実現します。
クライアント(Client):
- 具体的なコマンドオブジェクトを作成し、その受信者を設定して、コマンドオブジェクトを呼び出し側に渡して実行させます。
実装
まず、コマンドとしてのインターフェースを作成しますOrder、次にリクエストとしてのStockクラスを作成します。エンティティコマンドクラスBuyStockとSellStock、実装したOrderインターフェースは、実際のコマンド処理を実行します。Brokerオブジェクトはコマンドパターンを使用して、コマンドのタイプに基づいてどのオブジェクトがどのコマンドを実行するかを決定します。
BrokerクラスはCommandPatternDemoクラスを使用してコマンドパターンを実演します。Brokerステップ 1
ステップ 1
ステップ 2
Order.java
public interface Order {
void execute();
}
ステップ 2
ステップ 3
Stock.java
public class Stock {
private String name = "ABC";
private int quantity = 10;
public void buy(){
System.out.println("Stock [ Name: "+name+",
Quantity: " + quantity +" ] bought");
}
public void sell(){
System.out.println("Stock [ Name: "+name+",
Quantity: " + quantity +" ] sold");
}
}
ステップ 3
インターフェースのエンティティクラスを作成します。Orderステップ 4
BuyStock.java
public class BuyStock implements Order {
private Stock abcStock;
public BuyStock(Stock abcStock){
this.abcStock = abcStock;
}
public void execute() {
abcStock.buy();
}
}
SellStock.java
public class SellStock implements Order {
private Stock abcStock;
public SellStock(Stock abcStock){
this.abcStock = abcStock;
}
public void execute() {
abcStock.sell();
}
}
ステップ 4
ステップ 5
Broker.java
import java.util.ArrayList;
import java.util.List;
public class Broker {
private List<Order> orderList = new ArrayList<Order>();
public void takeOrder(Order order){
orderList.add(order);
}
public void placeOrders(){
for (Order order : orderList) {
order.execute();
}
orderList.clear();
}
}
ステップ 5
ステップ 6
CommandPatternDemo.java
public class CommandPatternDemo {
public static void main(String[] args) {
Stock abcStock = new Stock();
BuyStock buyStockOrder = new BuyStock(abcStock);
SellStock sellStockOrder = new SellStock(abcStock);
Broker broker = new Broker();
broker.takeOrder(buyStockOrder);
broker.takeOrder(sellStockOrder);
broker.placeOrders();
}
}
ステップ 6
その他の拡張
Stock [ Name: ABC, Quantity: 10 ] bought Stock [ Name: ABC, Quantity: 10 ] soldAI 思考中...