В Ruby, як і в багатьох інших
об'єктно-орієнтованих мовах програмування, наслідування - це механізм, за допомогою якого клас може успадковувати властивості та методи іншого класу. Клас, який успадковує, називається підкласом, а клас, від якого успадковується, - батьківським класом.
Приклад поганого наслідування в Ruby
class Animal
def speak
puts "Animal speaks"
end
end
class Dog < Animal
def speak
puts "Dog barks"
end
end
class Cat < Animal
# Цей клас не визначає свій власний метод speak
end
У цьому прикладі клас
Dog успадковує клас
Animal, але клас
Cat не надає свою власну реалізацію методу
speak. Якщо ви спробуєте створити екземпляр класу
Cat і викликати метод
speak, він використовуватиме реалізацію з класу
Animal. Це може бути проблемою, оскільки для кота більше властива відповідь -
meow.
Тобто ми очікуємо отримати текст 'Cat meows', а отримаємо 'Animal speaks'. Здається що це не дуже критично, але в класах, які відповідають за бізнес логіку це може привести до більших проблем.
Ми можемо зробити наступне:
class Cat < Animal
def speak
puts "Cat meows"
end
end
Це наче вирішує проблему. Але уявіть що класів і методів десятки або сотні. Цей підхід не є best practice.
Приклад гарного наслідування в Ruby
class Shape
def initialize(color)
@color = color
end
def draw
puts "Drawing a #{@color} shape"
end
end
class Circle < Shape
def initialize(color, radius)
super(color)
@radius = radius
end
def draw
puts "Drawing a #{@color} circle with radius #{@radius}"
end
end
class Square < Shape
def initialize(color, side_length)
super(color)
@side_length = side_length
end
def draw
puts "Drawing a #{@color} square with side length #{@side_length}"
end
end
У цьому прикладі є клас
Shape, який є базовим класом для всіх геометричних фігур. Клас має атрибут
color та метод
draw, який виводить повідомлення про малювання.
Класи Circle та Square успадковують клас Shape і надають власні атрибути (radius та side_length) та реалізацію методу draw. Кожен клас може викликати метод draw, але з власним контекстом та даними.
Цей підхід дозволяє створювати загальні властивості та методи в базовому класі, а потім розширювати їх у підкласах, забезпечуючи власну унікальну логіку. Це робить код більш читабельним, підтримуваним та гнучким.