俺の新 Git コース見てよ! おーい!俺の新 Git コース見てよ! おーい!GitByBit.com に俺の新 Git コースあるよ、見てみ! おーい!Git をサクッと復習したい?GitByBit.com の俺の新コース見てみ!
Command

Command を Ruby で

Command は、 振る舞いに関するデザインパターンの一つで、 リクエストや簡単な操作をオブジェクトに変換します。

変換により、 コマンドの遅延実行や遠隔実行を可能にしたり、 コマンドの履歴の保存を可能にしたりできます。

複雑度:

人気度:

使用例: Command パターンは、 Ruby コードではよく見かけます。 最もよく使われるのは、 UI 要素をアクションでパラメーター化する時のコールバックの代わりとしてです。 また、 タスクをキューに入れたり、 操作履歴の管理などでも使われます。

見つけ方: Command パターンは、 抽象またはインターフェース型 (送り手) 中の行動的メソッド (複数) が違う抽象またはインターフェース型 (受け手) 中のある一つのメソッドを起動することから識別できます。 受け手は、 生成時にコマンドの実装によりカプセル化されています。 コマンドのクラスは通常特定のアクションに限定されています。

概念的な例

この例は、 Command デザインパターンの構造を説明するためのものです。 以下の質問に答えることを目的としています:

  • どういうクラスからできているか?
  • それぞれのクラスの役割は?
  • パターンの要素同士はどう関係しているのか?

main.rb: 概念的な例

# The Command interface declares a method for executing a command.
class Command
  # @abstract
  def execute
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

# Some commands can implement simple operations on their own.
class SimpleCommand < Command
  # @param [String] payload
  def initialize(payload)
    @payload = payload
  end

  def execute
    puts "SimpleCommand: See, I can do simple things like printing (#{@payload})"
  end
end

# However, some commands can delegate more complex operations to other objects,
# called "receivers".
class ComplexCommand < Command
  # Complex commands can accept one or several receiver objects along with any
  # context data via the constructor.
  def initialize(receiver, a, b)
    @receiver = receiver
    @a = a
    @b = b
  end

  # Commands can delegate to any methods of a receiver.
  def execute
    print 'ComplexCommand: Complex stuff should be done by a receiver object'
    @receiver.do_something(@a)
    @receiver.do_something_else(@b)
  end
end

# The Receiver classes contain some important business logic. They know how to
# perform all kinds of operations, associated with carrying out a request. In
# fact, any class may serve as a Receiver.
class Receiver
  # @param [String] a
  def do_something(a)
    print "\nReceiver: Working on (#{a}.)"
  end

  # @param [String] b
  def do_something_else(b)
    print "\nReceiver: Also working on (#{b}.)"
  end
end

# The Invoker is associated with one or several commands. It sends a request to
# the command.
class Invoker
  # Initialize commands.

  # @param [Command] command
  def on_start=(command)
    @on_start = command
  end

  # @param [Command] command
  def on_finish=(command)
    @on_finish = command
  end

  # The Invoker does not depend on concrete command or receiver classes. The
  # Invoker passes a request to a receiver indirectly, by executing a command.
  def do_something_important
    puts 'Invoker: Does anybody want something done before I begin?'
    @on_start.execute if @on_start.is_a? Command

    puts 'Invoker: ...doing something really important...'

    puts 'Invoker: Does anybody want something done after I finish?'
    @on_finish.execute if @on_finish.is_a? Command
  end
end

# The client code can parameterize an invoker with any commands.
invoker = Invoker.new
invoker.on_start = SimpleCommand.new('Say Hi!')
receiver = Receiver.new
invoker.on_finish = ComplexCommand.new(receiver, 'Send email', 'Save report')

invoker.do_something_important

output.txt: 実行結果

Invoker: Does anybody want something done before I begin?
SimpleCommand: See, I can do simple things like printing (Say Hi!)
Invoker: ...doing something really important...
Invoker: Does anybody want something done after I finish?
ComplexCommand: Complex stuff should be done by a receiver object
Receiver: Working on (Send email.)
Receiver: Also working on (Save report.)

他言語での Command

Command を C# で Command を C++ で Command を Go で Command を Java で Command を PHP で Command を Python で Command を Rust で Command を Swift で Command を TypeScript で