我喜欢Ruby和我学习设计模式。这是Command Pattern的一个例子。域模型如下:
以下是此问题的一些代码:
class TV
def on
puts 'TV is on'
end
def off
puts 'TV is off'
end
end
class Command
class Error < StandardError; end
def execute
raise Error
end
end
class OnCommand < Command
attr_reader :tv
def initialize(tv)
@tv = tv
end
def execute
tv.on
end
end
class OffCommand < Command
attr_reader :tv
def initialize(tv)
@tv = tv
end
def execute
tv.off
end
end
class Button
attr_reader :command
def initialize(command)
@command = command
end
def execute_command
command.execute
end
end
class RemoteControl
attr_reader :tv
def initialize(tv)
@tv = tv
@buttons = {
on: Button.new(OnCommand.new(tv)),
off: Button.new(OffCommand.new(tv))
}
end
def use_button(name)
button(name).execute_command
end
private
def button(name)
@buttons.fetch name
end
end
以下是用法示例:
tv = TV.new
remote_control = RemoteControl.new(tv)
remote_control.use_button(:on) # TV is on
remote_control.use_button(:off) # TV is off
我对Command Pattern有多了解?这是一个很好的例子吗?
感谢任何想法
已更新
我想用 InfraredTransmitter 替换电视,因为命令接收器会使示例更合适。因为只有电视本身可以执行&#34; on&#34;命令。 RemoteControl可以物理访问其红外发射器,可以向电视发送不同的命令。
答案 0 :(得分:1)
Command
不应该引用TV
。这是不一个命令,它是一个 tv-only 命令。这是更多的红宝石方法:
class Command
def call(*args, &cb)
target, command, *rest = *args
target.public_send command, *rest, &cb
end
end
%i|on off|.each do |command|
const_set("Command#{command.to_s.capitalize}", Class.new(Command) do
def call(*args, &cb)
target, *rest = *args
super(target, command, *rest, &cb)
end
end
end
class Button
attr_reader :command
def initialize(command) # accepts :on, "on", CommandOn
@command = case command
when Class then command
when Symbol, String
const_get("Command#{command.to_s.capitalize}")
end.new
end
def call(target, *args, &cb)
command.(target, *args, &cb)
end
end
class RemoteControl
def initialize(tv)
@tv = tv
@buttons = %i|on off|.map { |c| [c, Button.new(c)] }.to_h
end
def call(command)
@buttons[command].(@tv)
end
end
remote_control = RemoteControl.new(TV.new)
remote_control.(:on)
remote_control.(:off)
使用这种方法,Command
可能会被重用于任何其他目标,而无需声明新的Command
。 必须目标不可知,否则它不是通用的Command
模式。
正如@Aetherus指出的那样,在这种方法中,根本不需要超类。可以安全地删除上面的Command
,除非你有一些共同的逻辑可以放在那里。
答案 1 :(得分:0)
对我来说是对的。
Command模式有以下参与者:
命令 - 声明用于执行操作的界面
ConcreteCommand - 定义Receiver对象与动作之间的绑定
客户端 - 创建一个ConcreteCommand对象并设置其接收方
祈求者 - 要求命令执行请求
接收方 - 知道如何执行与执行请求相关的操作
因此,在您的示例中,命令是命令, OnCommand , OffCommand 是 ConcreteCommand( s),电视 接收器,按钮 投影仪, RemoteControl 客户。
答案 2 :(得分:0)
您不需要超类Command
。只需定义那些具体的命令。那就是动态编程语言的运作方式。他们不关心类型。他们只关心对象是否具有所需的方法。