【问题标题】:ruby dynamic class instance creationruby 动态类实例创建
【发布时间】:2014-12-17 21:10:17
【问题描述】:

我正在编写一个棋盘游戏,作为 Ruby OOP 学习练习的一部分。我正在尝试创建一个游戏板,该游戏板由九个空间组成,三排三排。下面是当前无法运行的代码的sn-p:

class Board

  def initialize()
    #dynamically creates instances of the Space class named @s1 through @s9 with #s 1-9 as the location parameter
    9.times do |x|
      x += 1
      y = "@s" + x.to_s
      instance_variable_set( y , x.to_s) = Space.new
    end
  end

  def print_board
    #prints a 3X3 grid containing each instance's location parameter
    puts "\n\n#{@s1.location}|#{@s2.location}|#{@s3.location}\n-----\n#{@s4.location}|#{@s5.location}|#{@s6.location}\n-----\n#{@s7.location}|#{@s8.location}|#{@s9.location}\n\n\n"
  end
end

class Space

  attr_accessor :location

  def initialize(location)
    @location = location
  end

end

board = Board.new
board.print_board

想要的输出是:

X|X|X
-----
X|X|X
-----
X|X|X

...但我不断收到与创建 Space 类实例相关的错误。我尝试了很多不同的东西,以至于我都记不起来了。我知道必须有一种方法可以做到这一点,但我是 Ruby 新手,这让我很困惑。我知道可以只创建 Space 类的 9 个单独实例,但这看起来既便宜又脏。

【问题讨论】:

  • 也许你想要instance_variable_set(y , Space.new(x.to_s))
  • ...Aaaaaand circle 得到 square...就是这样。我是如此接近!如何将其标记为解决方案?
  • 您真的不想为每个单元格设置单独的变量。拥有一个数组或哈希的单一实例变量要好得多。
  • 为什么会这样(我是派对新手)?练习是创建一个井字游戏,虽然这很容易通过程序完成(不是使用数组/哈希使任何程序化),但练习的目标是学习 OOP,所以我试图最大限度地利用我/掌握/通过实践理解对象和相关事物。
  • @spectre6000 数组旨在通过索引(例如 1..9)访问对象。将索引放在变量名中并使用instance_variable_set 具有相同的效果,但它真的很hacky,可能会导致很多意想不到的问题。

标签: ruby oop


【解决方案1】:

这是一个稍微重新设计的、更 Ruby 风格的版本:

class Board
  def initialize
    @board = Array.new(9) do
      Space.new
    end
  end

  def move(x,y,set)
    @board[(x - 1) + (y - 1) * 3].location = set
  end

  def to_s
    @board.each_slice(3).collect do |row|
      row.join('|')
    end.join("\n------\n") + "\n"
  end
end

class Space
  attr_accessor :location

  def initialize(location = nil)
    @location = location || ' '
  end

  def to_s
    @location
  end
end

board = Board.new
puts board.to_s

board.move(1,2,'x')
puts board.to_s

值得注意的几个技巧:

  • Array.new 接受关于预填充多少条目的参数。
  • 可以为数组指定一个块进行评估,该块提供用于默认条目的值。
  • each_slice 提取 N 个条目组进行处理。
  • collect 将每一行转换为一个简单的字符串。
  • join 将行与水平线组合在一起。
  • to_s 是“显示为字符串”的默认名称,除非令人困惑,否则应使用该名称。
  • Space 需要 nil 的默认值作为初始值设定项
  • 不带参数的方法不需要括号,因此initializer 优于initializer()

您使用instance_variable_set 所采用的方法更难维护,并且由于具有代表单元格的九个 变量而违反了Zero, One or Infinity Rule。您需要的是一个理论上无限大小的变量,仅受您在必要时施加的约束的限制。拥有多个变量会使事情变得更加难以迭代,不方便作为参数传递,并且通常会使本来应该简单的事情变得一团糟。

【讨论】:

    猜你喜欢
    • 2020-05-11
    • 2015-12-17
    • 1970-01-01
    • 2020-06-22
    • 1970-01-01
    • 1970-01-01
    • 2017-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多