Используйте class_variable_get
, но только если вы должны
class_variable_get
является лучшим способом, за исключением того факта, что он не «привлекательный» для вас. Если вы входите в класс и нарушаете инкапсуляцию, возможно, уместно иметь этот дополнительный барьер, чтобы указать, что вы делаете что-то не так.
Создание методов доступа для переменных, к которым вы хотите получить доступ
Если это ваши классы, и доступ к переменным не нарушает инкапсуляцию, тогда вы должны создать методы доступа к ним, чтобы сделать их проще и красивее:
class Foo
def self.bar
@@bar
end
end
p Foo.bar
Однако, если это ваш класс, вы уверены, что вам нужны переменные класса? Если вы не понимаете последствий (см. Ниже), возможно, вам действительно нужны переменные экземпляра самого класса:
class Foo
class << self
attr_accessor :bar
end
end
Foo.bar = 42
p Foo.bar
Поведение переменных класса
Переменные класса кажутся новичкам как правильный способ хранения информации на уровне класса, в основном из-за названия. Они также удобны, потому что вы можете использовать один и тот же синтаксис для чтения и записи, независимо от того, используете ли вы метод класса или метод экземпляра. Однако переменные класса являются общими для класса и всех его подклассов.
Например, рассмотрим следующий код:
class Rectangle
def self.instances
@@instances ||= []
end
def initialize
(@@instances ||= []) << self
end
end
class Square < Rectangle
def initialize
super
end
end
2.times{ Rectangle.new }
p Rectangle.instances
#=> [#<Rectangle:0x25c7808>, #<Rectangle:0x25c77d8>]
Square.new
p Square.instances
#=> [#<Rectangle:0x25c7808>, #<Rectangle:0x25c77d8>, #<Square:0x25c76d0>]
Ack! Прямоугольники не квадраты! Вот лучший способ сделать то же самое:
class Rectangle
def self.instances
@instances ||= []
end
def initialize
self.class.instances << self
end
end
class Square < Rectangle
def initialize
super
end
end
2.times{ Rectangle.new }
p Rectangle.instances
#=> [#<Rectangle:0x25c7808>, #<Rectangle:0x25c77d8>]
2.times{ Square.new }
p Square.instances
#=> [#<Square:0x25c76d0>, #<Square:0x25c76b8>]
Путем создания переменной экземпляра и методов accesor для самого класса, который является экземпляром класса Class
, аналогично MyClass = Class.new
- всем экземплярам класса (и посторонним ) иметь общее чистое место для чтения / записи информации, которая не используется другими классами.
Обратите внимание, что явное отслеживание каждого созданного экземпляра предотвратит сборку мусора в «неиспользуемых» экземплярах. Осторожно используйте код, подобный приведенному выше.
Использование class_eval
более чистым способом
Наконец, если вы собираетесь использовать class_eval
, обратите внимание, что он также имеет блочную форму, которая не должна анализировать и лексировать строку для ее оценки:
Foo.class_eval('@@bar') # ugh
Foo.class_eval{ @@bar } # yum