# Commandパターン # # Java言語で学ぶデザインパターンと同様の例題をRubyで記述した。 # # coded by Takehiro Kaga # # Ruby/Tk の場合、簡単になり、DrawCommandクラス、MacroCommandクラス # を用意し、無名のメインロジックにて動作を示している # require 'tk' # コマンドクラスを定義する。その中にexecuteメソッドを定義する class DrawCommand def initialize(canvas, x, y) @canvas = canvas @x = x @y = y end attr_reader :canvas, :x, :y # マウスの位置を中心に半径6の円を白色で表示する # タグを付けておいて、消去などを可能とする def execute item1 = TkcOval.new(canvas, x-6, y-6, x+6, y+6, 'fill'=>'white', 'outline'=>'white') item1.addtag('item') end end class MacroCommand def initialize # 命令の集合を用意 @commands = Array.new end def execute # 実行 @commands.each {|command| command.execute } end def append(cmd) # 追加 @commands.push(cmd) end def undo # 最後の命令を削除 if !@commands.empty? commands.pop end end def clear # 全部削除 commands.clear end def historyget # @ommandsをゲット @commands end end # --- これよりメインロジック  --- # # 400x400のキャンバスを背景色ブルーで作る cv = TkCanvas.new(nil, 'height'=>400, 'width'=>400, 'background'=>'blue') # コマンドを蓄積するためのhistoryを定義する history = MacroCommand.new # キャンバスからタグ'item'で示されるものを消去するための釦を作る TkFrame.new{|f| TkButton.new(f, 'text'=>'clear ', 'command'=>proc{ cv.delete('item') } ).pack('side'=>'left') TkButton.new(f, 'text'=>'replay', 'command'=>proc{ history.execute } ).pack('side'=>'left') }.pack cv.pack # マウスの左ボタン(B1)を押したままドラッグした時、マウスの座標(x, y)を # パラメータにしてDrawCommandを生成、historyに蓄積するとともに、実行する cv.bind( 'B1-Motion', proc{|x, y| cmd = DrawCommand.new(cv, x, y); history.append(cmd); cmd.execute}, "%x %y" ) Tk.mainloop