Что означает принцип открытости и закрытости (Open/Closed Principle)?
Sobes Copilot
Get answers in real time
Answer from AI
sobes.tech AI
Принцип открытости/закрытости (Open/Closed Principle, OCP) формулируется так: программные сущности (классы, модули, функции и т.д.) должны быть открыты для расширения, но закрыты для модификации.
Это означает, что:
- Открыты для расширения: Поведение модуля можно расширять без изменения его исходного кода. Можно добавлять новую функциональность.
- Закрыты для модификации: После разработки и тестирования класса его интерфейс и реализация не должны изменяться для добавления новых возможностей. Изменение может привести к появлению ошибок в существующих частях системы.
OCP часто достигается за счет использования абстракций (интерфейсов, абстрактных классов) и полиморфизма. Вместо прямой зависимости от конкретной реализации, модуль зависит от абстракции. Новая функциональность добавляется путем создания новой реализации этой абстракции, а не путем изменения существующих классов.
Пример: До:
class ReportGenerator {
func generateReport(type: String) -> Data {
if type == "CSV" {
// Логика создания CSV
return Data() // Возвращаем фиктивные данные
} else if type == "PDF" {
// Логика создания PDF
return Data() // Возвращаем фиктивные данные
}
return Data()
}
}
В этом случае, для добавления нового формата отчета (например, JSON), нужно модифицировать существующий метод generateReport, что нарушает OCP.
После (с применением OCP):
// Абстракция
protocol ReportFormatter {
func format(data: Any) -> Data
}
// Конкретные реализации
class CSVReportFormatter: ReportFormatter {
func format(data: Any) -> Data {
// Логика создания CSV
return Data() // Возвращаем фиктивные данные
}
}
class PDFReportFormatter: ReportFormatter {
func format(data: Any) -> Data {
// Логика создания PDF
return Data() // Возвращаем фиктивные данные
}
}
class ReportGenerator {
private let formatter: ReportFormatter
init(formatter: ReportFormatter) {
self.formatter = formatter
}
func generateReport(data: Any) -> Data {
return formatter.format(data: data)
}
}
// Использование:
// Для CSV
// let csvFormatter = CSVReportFormatter()
// let csvGenerator = ReportGenerator(formatter: csvFormatter)
// csvGenerator.generateReport(data: someData)
// Для PDF
// let pdfFormatter = PDFReportFormatter()
// let pdfGenerator = ReportGenerator(formatter: pdfFormatter)
// pdfGenerator.generateReport(data: someData)
// Для добавления JSON: создать JSONReportFormatter, реализующий ReportFormatter
Теперь для добавления нового формата отчета достаточно создать новый класс, реализующий протокол ReportFormatter. Существующий ReportGenerator при этом не меняется.