Я только что выполнил ваш 2-й (полный) пример.
Помимо проблемы доступа, описанной в других ответах (просто добавьте attr_reader :protection
к классу Armor
), вы что-то упустили в тестовом сценарии :)
Сообщение об ошибке дает подсказку: undefined method 'protection' for nil:NilClass (NoMethodError)
.Учитывая, что это вызвано в 1-й строке метода hit
, это означает, что @armor
было nil
, и, конечно, nil
не является экземпляром Armor
, поэтому у него нет метода protection
.Почему это было ноль?Ну, посмотри, как начинается твой бой:
player1 = Player.new("Melanie", 100)
player2 = Player.new("a Monster", 200)
shirt = Armor.new('shirt', 4)
player1.equip(shirt)
Только у Мелани есть рубашка, а ты вообще не дал доспеху монстра!Это не очень справедливо:)
Чтобы это исправить, вам нужно либо дать ему немного доспехов, либо изменить свой метод hit
, чтобы он все еще работал, когда @armor
не был инициализирован.Хороший ОО способ сделать это состоит в том, чтобы инициализировать всех игроков с фиктивной броней по умолчанию, которая не обеспечивает защиту:
class Player
def initialize(name, health)
@armor = Armor.new('nothing', 0)
# ...
Готово!
Теперь,поскольку эта фиктивная броня будет полезна, какими бы ни были конкретные правила вашей игры, я бы абстрагировал ее с точки зрения класса Player
, сделав вместо этого класс Armor
ответственным за ее создание:
class Armor
class << self # define a class method, like new
def none
self.new('nothing', 0)
end
end
# ...
Тогда вы можете просто сказать Armor.none
вместо Armor.new('nothing', 0)
в Player.initialize
.Таким образом, если вам нужно изменить внутреннюю работу Armor
, вы можете обновить фиктивную броню одновременно, не затрагивая другие классы.