Возможно (но нежелательно) сделать именно то, что вы просите.
Есть два разных элемента желаемого поведения. Первый хранит x
в значении только для чтения, а второй защищает геттер от изменения в подклассах.
Значение только для чтения
В Ruby можно сохранять значения только для чтения во время инициализации. Для этого мы используем поведение закрытия блоков Ruby.
class Foo
def initialize (x)
define_singleton_method(:x) { x }
end
end
Начальное значение x
теперь заблокировано внутри блока, который мы использовали для определения геттера #x
, и к нему нельзя получить доступ, кроме как с помощью вызова foo.x
, и его нельзя изменить.
foo = Foo.new(2)
foo.x # => 2
foo.instance_variable_get(:@x) # => nil
Обратите внимание, что она не хранится как переменная экземпляра @x
, но по-прежнему доступна через геттер, который мы создали с помощью define_singleton_method
.
Защита получателя
В Ruby почти любой метод любого класса может быть перезаписан во время выполнения. Есть способ предотвратить это с помощью хука method_added
.
class Foo
def self.method_added (name)
raise(NameError, "cannot change x getter") if name == :x
end
end
class Bar < Foo
def x
20
end
end
# => NameError: cannot change x getter
Это очень жесткий метод защиты геттера.
Это требует, чтобы мы добавили каждый защищенный геттер в хук method_added
по отдельности, и даже в этом случае вам нужно будет добавить еще один уровень защиты method_added
для Foo
и его подклассов, чтобы кодер не перезаписал сам метод method_added
.
Лучше смириться с тем фактом, что замена кода во время выполнения — это факт жизни при использовании Ruby.
person
user513951
schedule
18.02.2014