#はじめに
現在デザインパターンについて勉強中です。
今回はCommandついてまとめました。
#Command
Commandはリクエストに必要な処理をオブジェクトとしてカプセル化し、必要に応じて実行するための、振る舞いに関するデザインパターンの一つです。
リクエストの処理と実行を分離することで、命令のキューイング、ロギング、アンドゥなどが可能になります。
例えば、プログラム内の全てのユーザの操作がCommandオブジェクトとして実装されれば、プログラムは最近実行されたコマンドのスタックを保持することができるようになります。
ユーザがコマンドをアンドゥする際、プログラムは最後に実行されたCommandオブジェクトを取得(pop)し、そのオブジェクトのundo()
メソッドを実行します。
#実装例
Command
パターンで銀行でのお金の預貯金機能を実装します。
リクエストの処理(deposit
, withdraw
)をBankAccount
クラス、実行(call
, undo
)をBankAccountCommand
クラスに実装します。
BankAccountCommand
でcall()
メソッドを実行する際に、コマンドが成功したかどうかをsucceed
で管理します。
こうすることで、succeed
がtrueの場合のみ、undo()
メソッドを実行されるようにできます。
class BankAccount
{
constructor(balance=0)
{
this.balance = balance;
}
deposit(amount)
{
this.balance += amount;
console.log(
`Deposited ${amount}, balance is now ${this.balance}`
);
}
withdraw(amount)
{
if (this.balance - amount >= BankAccount.overdraftLimit)
{
this.balance -= amount;
console.log(
`Withdrew ${amount}, balance is now ${this.balance}`
);
return true;
}
return false;
}
toString()
{
return `Balance: ${this.balance}`;
}
}
BankAccount.overdraftLimit = -500;
let Action = Object.freeze({
'deposit': 1,
'withdraw': 2
});
class BankAccountCommand
{
constructor(account, action, amount)
{
this.account = account;
this.action = action;
this.amount = amount;
this.succeeded = false;
}
call()
{
switch (this.action)
{
case Action.deposit:
this.account.deposit(this.amount);
this.succeeded = true;
break;
case Action.withdraw:
this.succeeded = this.account.withdraw(this.amount);
break;
}
}
undo()
{
if (!this.succeeded) return;
switch (this.action)
{
case Action.deposit:
this.account.withdraw(this.amount);
break;
case Action.withdraw:
this.account.deposit(this.amount);
break;
}
}
}
以下のように、インスタンスを作ってcall()
とundo()
を実行します。
let ba = new BankAccount(100);
let cmd = new BankAccountCommand(ba, Action.deposit, 50);
cmd.call();
console.log(ba.toString());
console.log('Performing undo:');
cmd.undo();
console.log(ba.toString());
すると、deposit
した分の残高balance
がアンドゥされたことを確認することができます。
Deposited 50, balance is now 150
Balance: 150
Performing undo:
Withdrew 50, balance is now 100
Balance: 100
#参考資料