Принцип відкритості/закритості (Open/Closed Principle - OCP) є одним з п’яти принципів SOLID і визначає, що класи повинні бути відкритими для розширення, але закритими для модифікацій. Це означає, що поведінка класу може бути розширена без зміни його вихідного коду.
Основні ідеї OCP.
- Відкритість для розширення - клас повинен надавати можливості для розширення свого поведінки. Це може бути досягнуто за допомогою інтерфейсів, абстракцій або використання паттернів проектування.
- Закритість для модифікацій - при цьому принципі клас повинен залишатися стійким до змін у своєму внутрішньому коді, тобто він закритий для модифікацій. Зміни повинні вноситися лише для введення нового функціоналу.
- Розширення за допомогою підкласів або інтерфейсів - новий функціонал додається шляхом створення нових класів (підкласів або об’єктів, що реалізують інтерфейси), які розширюють базовий клас, не модифікуючи його.
В Ruby принцип відкритості/закритості (OCP) також можна продемонструвати за допомогою інтерфейсів або поліморфізму. Ось приклад:
# Закритий для модифікацій клас
class Circle
attr_reader :radius
def initialize(radius)
@radius = radius
end
def area
Math::PI * radius**2
end
end
# Відкритий для розширення інтерфейс
module Shape
def area
raise NotImplementedError, 'Subclasses must implement the area method'
end
end
# Розширення нового функціоналу через новий клас
class ColoredCircle < Circle
attr_reader :color
def initialize(radius, color)
super(radius)
@color = color
end
def area
# Використовуємо функціонал базового класу Circle
super
end
end
# Використання розширеного функціоналу
circle = ColoredCircle.new(5, 'red')
puts "Colored Circle Area: #{circle.area}" # Використовує функціонал базового класу
puts "Color: #{circle.color}"
У цьому прикладі клас Circle
є закритим для модифікацій, і його функціонал розширюється за допомогою нового класу ColoredCircle
. ColoredCircle
успадковує Circle
і реалізує інтерфейс Shape
, в якому обов’язково повинен бути метод area
. Таким чином, принцип відкритості/закритості дотримується: ми можемо розширити функціонал, не модифікуючи вихідний код Circle
.