Если вы посмотрите на документацию Module#attr
, вы увидите, что есть три "перегрузки" для его использования:
attr(name, …)
→ nil
attr(name, true)
→ nil
attr(name, false)
→ nil
Затем в документации дополнительно объясняются различия между ними:
Первая форма эквивалентна attr_reader
. Вторая форма эквивалентна attr_accessor(name)
, но устарела. Последняя форма эквивалентна attr_reader(name)
, но устарела.
Итак, первая и третья формы порождают только читателей, а не писателей. Вторая форма генерирует читателя и писателя, но она принимает только один name
формальный параметр, вы не можете использовать его для создания нескольких атрибутов.
Кроме того, формы две и три устарели, и все три формы не являются идиоматическими.
Если вы хотите исправить свой код, используя не-идиоматический Module#attr
, вам нужно сделать это:
attr :name , true
attr :age , true
attr :gender, true
Вы можете немного упростить это, используя что-то вроде
%i[name age gender].each do |attribute|
attr attribute, true
end
Однако, как упоминалось в документации, эта форма устарела, и, как я упоминал ранее, Module#attr
не является идиоматическим.
Идиоматическим способом является использование семейства методов Module#attr_*
, то есть Module#attr_reader
, Module#attr_writer
и Module#attr_accessor
:
attr_accessor :name, :age, :gender
Обратите внимание, что поскольку ваш класс Person
фактически не имеет никакого поведения, вы можете просто заменить его на Struct
:
Person = Struct.new(:name, :age, :gender)
Однако обратите внимание, что средства доступа вообще и авторы в частности не являются хорошим объектно-ориентированным проектом. Объекты должны делать что-то, они должны иметь поведение . Ваши Person
объекты не имеют никакого поведения, они просто содержат данные. Кроме того, объект должен быть действительным после его создания, но ваши объекты Person
будут пустыми при их создании. И наконец, если это вообще возможно, объекты должны быть неизменными .
Мы можем убедиться, что объект действителен после создания, добавив инициализатор:
class Person
attr_accessor :name, :age, :gender
def initialize(name, age, gender)
self.name, self.age, self.gender = name, age, gender
end
end
person = Person.new('John', 55, 'male')
Примечание: Struct
создаст для нас инициализатор.
Если мы хотим сделать объект неизменным, нам нужно удалить писателей (или сделать их private
). К сожалению, Struct
не сделает это для нас:
class Person
attr_reader :name, :age, :gender
private
attr_writer :name, :age, :gender
def initialize(name, age, gender)
self.name, self.age, self.gender = name, age, gender
end
end
person = Person.new('John', 55, 'male')
Теперь person
полностью инициализируется после его создания и больше не может быть изменен.