Нещодавно ми говорили, що Ruby не має функцій, тільки методи. Однак є більш ніж один вид методів. У цьому розділі ми ознайомимося з контролем доступу.
Розглянемо, що відбувається, коли визначаємо метод верхньому рівні, не всередині визначення класу. Ми можемо подумати, що цей метод буде аналогічним до функцій у більш традиційній мові, такій як C.
ruby> def square(n) | n * n | end nil ruby> square(5) 25
Наш новий метод, як здається, не належить жодному класу, але фактично рубає дає йому клас Object , який є суперкласом для кожного іншого класу. В результаті будь-який об'єкт зможе використовувати цей метод. Це справедливо, але є невелика проблема: це приватний спосіб кожного класу. Ми обговоримо, що це означає нижче, але одним із наслідків цього є те, що він може бути викликаний тільки в стилі функції, як тут:
ruby> class Foo | def fourth_power_of(x) | square(x) * square(x) | end | end nil ruby> Foo.new.fourth_power_of 10 10000
Нам не дозволяється виконувати цей метод як метод об'єкта:
ruby> "fish".square(5) ERR: (eval):1: private method `square' called for "fish":String
Це зберігає Об'єктно-орієнтовану природу Ruby більш чистої (функції все ще є методами об'єкта, але приймачем неявно є * self *) у той час як функції можуть бути написані як у традиційній мові.
Традиційним підходом в об'єктно-орієнтованому програмуванні, про яке ми натякали в недавніх розділах, є поділ на специфікацію та імплементацію, або які завдання об'єкта передбачається виконувати і як вони насправді виконуються. Внутрішня робота об'єкта повинна зберігатися, зазвичай, прихованої від користувачів. Вони повинні піклуватися тільки про те, які дані виходять і виходять в об'єкт, і вірити тому, що об'єкт знає, що робити з даними всередині себе. Таким чином, часто буває корисним для класів мати методи, які не видно зовнішнього світу, але які використовуються всередині (і можуть бути покращені програмістом, коли він побажає, без зміни бачення користувачами об'єкта зовні. У звичайному прикладі, що слідує далі, думаємо про engine як про невидимого внутрішнього працівника класу.
ruby> class Test | def times_two(a) | print a," times two is ",engine(a),"\n" | end | def engine(b) | b*2 | end | private:engine # this hides engine from users | end Test ruby> test = Test.new #<Test:0x4017181c> ruby> test.engine(6) ERR: (eval):1: private method `engine' called for #<Test:0x4017181c> ruby> test.times_two(6) 6 times two is 12. nil
Ми могли б очікувати виконання test.engine(6) для повернення значення 12, але натомість ми бачимо, що engine недоступний, коли користувач застосовує його до екземпляра класу Test . Тільки іншим методам класу Test , таким як times_two , дозволяється використовувати engien . Нам потрібно використовувати публічний інтерфейс, який міститься в методі times_two. не торкаючись того, як користувач взаємодіє з об'єктами Test.* Цей приклад, звичайно, дуже простий, щоб бути корисним; переваги контролю доступу стають більш зрозумілими лише тоді, коли ми починаємо створювати складніші та цікавіші класи.