【发布时间】:2016-01-07 00:49:31
【问题描述】:
现在我终于弄清楚了 ruby 中类继承的工作原理,我正在为文本 rpg 设计一个库存系统。但是,有些怪癖我无法弄清楚。
物品类别:
class Item
attr_accessor :name, :type, :attack, :armor, :wearloc, :weight, :price
def initialize(name, type, attack, armor, wearloc, weight, price)
@name = name
@type = type
@attack = attack
@armor = armor
@wearloc = wearloc
@weight = weight
@price = price
end
end
库存类:
class Inventory
attr_accessor :items
def initialize
@@items = []
end
def add_item(item)
@@items << item
end
attr_accessor :inventory
def inventory
@@items.each do |item|
puts "#{item.name} (#{item.type})"
if item.attack != nil ; puts " %-20s %00d" % ['Attack', item.attack] ; end
if item.armor != nil ; puts " %-20s %00d" % ['Armor', item.armor] ; end
if item.wearloc != nil ; puts " %-20s %00s" % ['Wear', item.wearloc] ; end
if item.weight != nil ; puts " %-20s %00d" % ['Weight', item.weight] ; end
if item.price != nil ; puts " %-20s %00d" % ['Price', item.price] ; end
end
end
end
播放器类:
class Player < Inventory
attr_accessor :playername
def initialize(playername)
@playername = playername
end
end
实例化清单,创建一些项目,将它们添加到清单中所有工作。
inv = Inventory.new
broadsword = Item.new('a heavy broadsword', 'weapon', 5, nil, 'wield', 15, 2)
breastplate = Item.new('a mithril breastplate', 'armor', nil, 10, 'torso', 15, 5)
ring = Item.new('a gold ring', 'armor', nil, 3, 'finger', 2, 20)
inv.add_item(broadsword)
inv.add_item(breastplate)
inv.add_item(ring)
但是,当我从 Player 类调用 inventory 方法时,我得到了所需的输出,以及 3 个 #item 对象,如下所示:
a heavy broadsword (weapon)
Attack 5
Wear wield
Weight 15
Price 2
a mithril breastplate (armor)
Armor 10
Wear torso
Weight 15
Price 5
a gold ring (armor)
Armor 3
Wear finger
Weight 2
Price 20
#<Item:0x007fae1b8b11d8>
#<Item:0x007fae1b8b1138>
#<Item:0x007fae1b8b1098>
为什么最后三行在那里?我不知道它来自哪里或如何解决它。
更新:
对 Item
class Player
attr_accessor :playername
def initialize(playername)
@playername = playername
end
end
class Inventory < Player
attr_accessor :items
def initialize
@items = []
end
def add_item(item)
@items << item
end
attr_accessor :inventory
def inventory
@items.each do |item|
puts "#{item.name} (#{item.type})"
if item.attack != nil ; puts " %-20s %00d" % ['Attack', item.attack] ; end
if item.armor != nil ; puts " %-20s %00d" % ['Armor', item.armor] ; end
if item.wearloc != nil ; puts " %-20s %00s" % ['Wear', item.wearloc] ; end
if item.weight != nil ; puts " %-20s %00d" % ['Weight', item.weight] ; end
if item.price != nil ; puts " %-20s %00d" % ['Price', item.price] ; end
end
nil
end
end
class Item < Inventory
attr_accessor :name, :type, :attack, :armor, :wearloc, :weight, :price
def initialize(name, type, attack, armor, wearloc, weight, price)
@name = name
@type = type
@attack = attack
@armor = armor
@wearloc = wearloc
@weight = weight
@price = price
end
end
inv = Inventory.new
broadsword = Item.new('a heavy broadsword', 'weapon', 5, nil, 'wield', 15, 2)
breastplate = Item.new('a mithril breastplate', 'armor', nil, 10, 'torso', 15, 5)
ring = Item.new('a gold ring', 'armor', nil, 3, 'finger', 2, 20)
inv.add_item(broadsword)
inv.add_item(breastplate)
inv.add_item(ring)
player = Player.new('Chris')
# puts player.inventory
puts inv.inventory
【问题讨论】:
-
如果你在 Ruby 中使用
@@class_variable,你会很不爽。 -
我关于不使用类变量的评论的一些参考:an ages-old O'Reilly article 和 this SO answer(不是公认的答案)
-
@Ekult3k:这些都不应该相互继承。物品不是一种库存,而是包含在库存中。物品栏不是一种玩家,它是由玩家携带的。因此,
Player内部应该有一个@inventory,Inventory内部应该有一个@items数组,通过方法或访问器公开。阅读“继承和组合”(Google 有无数链接)。 -
@oorahduc:正如我所说,阅读组合和继承 - 你不必相信我的话。继承适用于“A 是 B 的一种”——Dog 是一种哺乳动物,ScreenWindow 是一种 ScreenWidget ... 组合(在实例变量中具有另一个类的实例)适用于“A 有 B”:Parent有一个 Childs 数组,Child 有一个母亲 Parent 和一个父亲 Parent,Unicycle 有一个 Wheel。
-
@Ekult3k:你的意见是错误的。继承的全部意义在于共享相关对象的行为。如果动物可以吃或死,那么哺乳动物可以吃或死,所以狗也可以吃或死。如果 ScreenWidget 可以隐藏自己,那么 ScreenWindow 也可以。如果 Item 继承自 Inventory,则 Item 具有 Inventory 的所有行为,例如如果你有
Inventory#clear!和Inventory#drop_random_item!,那么你也有Item#clear!和Item#drop_random_item!,这是没有意义的。
标签: ruby inheritance system