Чи замислювалися ви, як працюють контролі доступу, такі як private і protected, у сучасних версіях Ruby?
Я помітив, що багато досвідчених розробників Ruby мають труднощі з поясненням ключових відмінностей між методами private та protected. Щоб пролити світло на це питання, я вирішив написати цю статтю.
Перш ніж заглиблюватися, давайте розглянемо кілька тверджень. Ми визначимо, які з них правильні, а які — ні:
- Публічні методи не мають контролю доступу. Їх можна викликати ззовні класу будь-яким екземпляром цього класу.
- Як protected, так і private методи не можна викликати ззовні визначеного класу.
- Методи protected доступні з підкласів, а методи private — ні.
- Методи private класу можна викликати будь-яким екземпляром цього класу.
- Публічний доступ є стандартним.
Розуміння специфікаторів доступу з прикладами коду
Давайте розглянемо фрагмент коду, щоб прояснити ці концепції. Зверніть увагу, що наступні приклади застосовуються до сучасних версій Ruby (>=2.7). Ruby 2.7 ввела деякі зміни в поведінку, які я поясню пізніше.
class Example
def public_method
"Привіт, там"
end
def invoke_private_method
private_method # неявний приймач
self.private_method # явний приймач (але все одно self)
end
def invoke_protected_method
protected_method # неявний приймач
self.protected_method # явний приймач (але все одно self)
end
private
def private_method
puts "Це приватно!"
end
protected
def protected_method
puts "Це захищено!"
end
end
example = Example.new
example.public_method # => працює; публічний доступ за замовчуванням
example.invoke_private_method # => працює (нова поведінка в Ruby 2.7 дозволяє це)
# Вивід
Це приватно!
Це приватно!
example.invoke_protected_method # => працює
# Вивід
Це захищено!
Це захищено!
example.private_method # => викликає NoMethodError (приватний метод)
example.protected_method # => викликає NoMethodError (захищений метод)
Інша версія прикладу
Тепер трохи змінимо приклад:
class Example
def invoke_private_method(obj)
obj.private_method # явний приймач (але не self)
end
def invoke_protected_method(obj)
obj.protected_method # явний приймач (але не self)
end
private
def private_method
puts "Це приватно!"
end
protected
def protected_method
puts "Це захищено!"
end
end
example = Example.new
example.invoke_private_method(example) # => викликає NoMethodError (приватний метод)
example.invoke_protected_method(example) # => працює
# Вивід
Це захищено!
Прояснення спадкування та специфікаторів доступу
Давайте розглянемо деякі поширені непорозуміння щодо спадкування та специфікаторів доступу за допомогою цієї нової версії:
class ChildExample < Example
def invoke_private_method_from_child
private_method # працює
self.private_method # працює
end
def invoke_protected_method_from_child
protected_method # працює
self.protected_method # працює
end
end
child_example = ChildExample.new
child_example.invoke_private_method_from_child # => працює
# Вивід
Це приватно!
Це приватно!
child_example.invoke_protected_method_from_child # => працює
# Вивід
Це захищено!
Це захищено!
Це демонструє, що доступ до приватних методів не залежить від спадкування.
Оцінка тверджень
Тепер давайте повернемося до початкових тверджень:
-
ПРАВДА — Публічні методи не мають контролю доступу.
-
ПРАВДА — Як protected, так і private методи не можна викликати ззовні визначеного класу.
-
НЕПРАВДА — Методи protected доступні з підкласів; методи private — ні.
-
НЕПРАВДА — Приватні методи визначеного класу можуть бути викликані будь-яким екземпляром цього класу.
5.
текст перекладу
TRUE — Загальнодоступність є стандартною.
Примітка: Наведені приклади працюють з Ruby 2.7 або новішими версіями, оскільки до Ruby 2.7 метод self.private_method не був дозволений. У старіших версіях це призводило до помилки NoMethodError. Деталі можна знайти за посиланням зміни в поведінці self
Основні висновки
-
Приватні методи не можна викликати з явним приймачем, тоді як захищені методи можна.
-
Приватні методи призначені для використання без явного приймача, щоб забезпечити інкапсуляцію.
-
Хоча `self.privatemethod`_ працює, це не є конвенційним і слід уникати цього для забезпечення чіткості коду.
Перекладено з: Mastering Ruby Access Specifiers (public, protected & private)