Принцип незалежних об’єктів (Dependency Inversion Principle - DIP) є одним з п’яти принципів SOLID і визначає, що модулі верхнього рівня не повинні залежати від модулів нижчого рівня. Обидва типи модулів повинні залежати від абстракцій. Також, деталі не повинні залежати від абстракцій, але абстракції повинні залежати від деталей.
Основні ідеї DIP.
Залежність від абстракцій - класи верхнього рівня повинні залежати від абстракцій (інтерфейсів чи абстрактних класів), а не від конкретних реалізацій (конкретних класів) нижчого рівня.
Введення абстракцій - абстракції повинні визначати важливі операції, а деталі мають залежати від цих абстракцій, а не навпаки.
Інверсія залежностей - модулі верхнього рівня не повинні контролювати деталі нижчого рівня; навпаки, обидва рівні повинні залежати від абстракцій.
В Ruby, принцип незалежних об’єктів (DIP) також може бути демонстрований за допомогою модулів та класів.
# Абстракція (модуль)
module SwitchableDevice
def turn_on
raise NotImplementedError, 'Subclasses must implement the turn_on method'
end
def turn_off
raise NotImplementedError, 'Subclasses must implement the turn_off method'
end
end
# Деталі нижчого рівня
class LightBulb
include SwitchableDevice
def turn_on
puts 'LightBulb: Bulb turned on...'
end
def turn_off
puts 'LightBulb: Bulb turned off...'
end
end
class Fan
include SwitchableDevice
def turn_on
puts 'Fan: Fan turned on...'
end
def turn_off
puts 'Fan: Fan turned off...'
end
end
# Клас верхнього рівня, який залежить від абстракції
class Switch
def initialize(device)
@device = device
end
def turn_on
@device.turn_on
end
def turn_off
@device.turn_off
end
end
# Використання принципу незалежних об'єктів
light_bulb = LightBulb.new
fan = Fan.new
light_switch = Switch.new(light_bulb)
fan_switch = Switch.new(fan)
light_switch.turn_on # Залежність від абстракції
light_switch.turn_off
fan_switch.turn_on
fan_switch.turn_off
В цьому прикладі Switch
- це модуль верхнього рівня, який залежить від абстракції SwitchableDevice
. Класи LightBulb
і Fan
реалізують цей модуль, що дозволяє їх використовувати як абстракції, а не конкретні реалізації. Такий підхід полегшує зміну та розширення системи, оскільки можна додавати нові пристрої, не змінюючи клас Switch
.