1. ホーム
  2. スクリプト・コラム
  3. ルビートピックス

Rubyのデザインパターンプログラミングにおけるコマンドパターンの活用を徹底分析

2022-01-31 01:03:18

Commandパターンは、オブジェクトの振る舞いの使用率が高いデザインパターンで、別名 Action、Transaction

意図: リクエストをオブジェクトにカプセル化することで、異なるリクエストをパラメータ化したり、リクエストをキューに入れたり、ログに記録したり、キャンセル可能なアクションをサポートしたりすることができます。
ここでいう「異なる要求」とは、要求の変更と、特徴点の拡張の両方を意味する。

動機 拡張しやすい

構造です。

コラボレーションの注意点
   参加した役割
    コマンド アクションを実装するために使用するインターフェイスを宣言する。
    ConcreteCommandは、Reciverに外部からアクションをバインドし、Reciverオブジェクトの適切なメソッドを呼び出して、Commandのメソッドを実装する。
    クライアントがConcreteCommandオブジェクトを作成し、そのReciverオブジェクトを設定する。
  InvokerはこのCommandにリクエストの実行を依頼する。
  Reciver 特定のリクエストを実装する方法を知っているクラス。
  クライアントは特定のCommandオブジェクトを作成し、その受信者を指定する。
  呼び出し側オブジェクトは、この具体的なCommandオブジェクトを格納する。
  呼び出し側オブジェクトは、CommandオブジェクトのExecuteメソッドを実行して、現在の要求を実行する。
  コマンドが取り消し可能な場合、具象オブジェクトはExecuteメソッドを呼び出す前に、この要求を命令するために使用する適切な状態を格納する。
  具体的なCommandオブジェクトは、その受信者のメソッドを呼び出して、要求を実現する。


適用範囲
MenuItemと同様に、オブジェクトをパラメータ化するために実行されるアクションを抽象化します。
異なる瞬間に要求を指定し、手配し、実行する
アンドゥに対応
ログの修正に対応
プロトスピーチ操作(実際にはトランザクション)の上に構築された高レベルの操作のシステム構築


力学面:rubyのブロックのようなコマンドモード

エフェクト
Commandパターンは、呼び出し側オブジェクトと受信側オブジェクトを切り離す(呼び出しと実装を切り離す)。呼び出し側は Command インターフェースの Execute メソッドを呼び出すだけで、機能を実装することができます。
具体的なCommandsオブジェクトは、他のオブジェクトと同様に拡張や操作が可能な第一レベルのオブジェクトです。
複数のCommandsオブジェクトを集約して、複合コマンドにすることができます。合成コマンドもCompositional Objectパターンのインスタンスであり、コマンドのキューイングはその特殊なケースです。
既存のコードを修正する必要がないため、新しいコマンドを簡単に追加することができます。これは、修正には閉じ、拡張には開くというオープン・クローズの原則にも合致しています。


コマンドオブジェクトがどのような知的処理を実現するか、アンドゥとリドゥのサポートという2つの課題を考慮した実装が必要です。


誤用です。
こだわらないこと とにかく簡単なのはどっち?
コマンドモードでは、「こうしてください」「こうやって覚えてください」「こうやってください」と言った後に、「さっき覚えてもらった通りにやってください」と言うことはありません。
アンドゥに注意、ファイルの削除など破壊的なアクションも多い


クラス図です。

class Button
 
 attr_accessor :name, :command
 
 def initialize name, command
  @name = name
  @command = command
 end
 
 def do_something
  @command.execute
 end
 
end

class Command
 
 def execute
  "root execute"
 end
 
end

class PaintCommand < Command
 
 def execute
  "draw something"
 end
 
end

class VocalCommand < Command
 
 def execute
  "talk something"
 end
 
end

paintCommand = PaintCommand.new
vocalCommand = VocalCommand.new
button = Button.new("button", paintCommand)
p button.do_something
button.command = vocalCommand
p button.do_something



 定義本体クラスボタンは、ボタンがコマンドオブジェクトを集約し、宣言コマンド、PaintCommand、VocalCommand継承と3つのコマンドクラスは、システム内の複数のボタンがありますが、それぞれのボタンが同じではないことを完了するには、この部分は、メソッドを行う_something内のコードも不確実である変更されていることです。この部分のコードは、管理のために別のオブジェクトに分離され、このオブジェクトは、コマンドオブジェクトと呼ばれ、コマンドオブジェクトは、完了する必要があるタスクや命令にのみ責任を負う、メインオブジェクトは、必要なコマンドを実行する彼らのニーズに応じて、いつでも呼び出すことができます。また、呼び出し時のコードから明らかなように、現在のButtonを切り替えるコマンドは、setメソッドを呼び出すだけで実現できる、非常に簡単で柔軟性の高いものです。もし、Buttonの継承の関係を利用すると、第一に主語となるオブジェクトがクラスの爆発を引き起こすこと、第二にコマンドの実装を切り替える際にこの方法では比較が困難であることが挙げられます。
ruby procを使って、コマンドモデルを完成させる。

class Button
 
 attr_accessor :name
 
 def initialize name, &command
  @name = name
 end
 
 def do_something &command
  command.call
 end
 
end

paint_command = lambda do
 p "paint something"
end

vocal_command = lambda do
  p "talk something"
end

button = Button.new ("name")
button.do_something &vocal_command
button.do_something &paint_command



 コマンドオブジェクトが非常に複雑で、独自のステートとメソッドを持つ必要がある場合は、コマンドクラスを使って完成させ、いくつかの小さなことを処理するだけの簡単なものであれば、procの
実行するコマンドが多すぎる場合は、コマンドキュー、つまり複数のコマンドを管理するコマンドを定義し、呼び出すと各コマンドを1つずつ呼び出して実行するという、ここからは組み合わせパターンに近い形になります
ObserverパターンとCommandパターンは、共通の性質を持つオブジェクトを独自のクラスに集約し、それを適宜呼び出すという点で、ある意味似ている。しかし、この2つのパターンには明らかな違いが1つあり、それは使用方法です。Observerパターンは被観測者が様々な異なるオブザーバーに変更を通知するために使われるのに対し、Commandパターンは他のコマンドに通知されても気にせず、コマンドオブジェクトは自分のタスクやコマンドの実行にのみ責任を持ち、コマンドパターンは前の操作を記憶するので、一般的に多くのテキストエディタはアンドゥ/リドゥにコマンドパターンを使っていると言われています。