【问题标题】:Composite of Commands Design Pattern命令设计模式的组合
【发布时间】:2012-05-20 14:42:37
【问题描述】:

有没有人在 Ruby 中使用命令组合的一个很好的例子?这是我在各种设计模式文献中看到的一种设计模式混合体,听起来很强大,但找不到任何有趣的用例或代码。

【问题讨论】:

  • 嗯,寻找问题的解决方案,嗯? ;)
  • 好点。也许一句话可以激发一些创新:“发现问题实际上需要与发现解决方案一样多的创造力。有很多方法可以看待任何问题,而意识到问题通常是迈向创造性解决方案的第一步。套用约翰杜威的话说,杜威十进制系统的发明者,一个正确定义的问题得到了部分解决。那么,创新的开始不应该从寻找完美的解决方案开始,而应该从寻找正确的问题开始。”
  • 这篇名为Design Patterns in Ruby - Composite, Iterator, Command (Part 2) 的博文分别包含这些模式的代码。
  • @maerics - 根据您的回答,您显然是在开玩笑,但拥有“寻找问题的解决方案”实际上很好 如果 1)这是一个很好的解决方案2)你很可能会遇到问题。这基本上就是设计模式的意义所在。

标签: ruby oop design-patterns ooad


【解决方案1】:

受一般想法和the sample pattern implementations in this blog post 的启发,下面是它的外观:

class CompositeCommand
  def initialize(description, command, undo)
    @description=description; @command=command; @undo=undo
    @children = []
  end
  def add_child(child); @children << child; self; end
  def execute
    @command.call() if @command && @command.is_a?(Proc)
    @children.each {|child| child.execute}
  end
  def undo
    @children.reverse.each {|child| child.undo}
    @undo.call() if @undo && @undo.is_a?(Proc)
  end
end

以及使用软件安装程序应用程序的示例用法:

class CreateFiles < CompositeCommand
  def initialize(name)
    cmd = Proc.new { puts "OK: #{name} files created" }
    undo = Proc.new { puts "OK: #{name} files removed" }
    super("Creating #{name} Files", cmd, undo)
  end
end

class SoftwareInstaller
  def initialize; @commands=[]; end
  def add_command(cmd); @commands << cmd; self; end
  def install; @commands.each(&:execute); self; end
  def uninstall; @commands.reverse.each(&:undo); self end
end

installer = SoftwareInstaller.new
installer.add_command(
  CreateFiles.new('Binary').add_child(
    CreateFiles.new('Library')).add_child(
    CreateFiles.new('Executable')))
installer.add_command(
  CreateFiles.new('Settings').add_child(
    CreateFiles.new('Configuration')).add_child(
    CreateFiles.new('Preferences')).add_child(
    CreateFiles.new('Help')))
installer.install # => Runs all commands recursively
installer.uninstall

【讨论】:

    【解决方案2】:

    我自己正在尝试理解这种模式,并且一直在考虑可以用这种方式建模哪些东西。

    复合模式的基本思想是在某些情况下需要以相同的方式处理项目和集合。集合可能包含项目和子集合的混合,嵌套的深度可以随意。

    我的一些想法(借用Design Patterns in RubyRuby Under a Microscope的一些想法):

    文件系统

    您可以询问文件的大小,它会返回一个简单的值。您还可以询问文件夹的大小,它会返回其文件和子文件夹大小的总和。子文件夹当然会返回其文件和子文件夹的总和。

    同样,文件和文件夹都可以移动、重命名、删除、备份、压缩等。

    系统命令

    一个命令对象可以有一个run 方法。该方法可以通过运行任意数量的子命令来工作,这些子命令具有子命令等。如果它的所有子命令都返回 true,它可以返回 true,并且可以根据其子命令的统计信息(经过的时间、修改的文件等)报告统计信息。

    公司层次结构

    个人、团队、部门和整个公司都可以被视为有薪水、带来收入、完成工作单元等。

    一个军事单位

    在游戏中,士兵可以拥有防御和进攻统计数据,可以被告知移动到某个位置、攻击基地等。团和师可以以同样的方式对待。

    重量或货币价值

    装满箱子的卡车的重量包括每个箱子的重量。每个盒子的重量包括它的每件物品的重量、它们的零件等。

    同样,金融投资组合的货币价值是其所有资产的价值。其中一些资产可能是包含多只股票的指数基金。您可以买卖单个股票或整个投资组合。

    GUI 元素

    一个窗口可以由框架组成,框架由框架组成,框架由框架组成。任何元素都可以定位、着色、聚焦、隐藏等。

    编程语言中的表达式

    当 Ruby 解释器评估一个表达式时,它会将其分解为一个表达式树(抽象语法树)并评估每个表达式,然后通过返回到顶部的方式得出最终值树。从某种意义上说,树的每一层都被问到同一个问题:“你的价值是什么?”

    举个简单的例子,求((4 + 8) * 2)) + 9的值的第一步就是求4 + 8的值。

    【讨论】: