Sobes.tech
Middle

What does the Open/Closed Principle mean?

sobes.tech AI

Answer from AI

The Open/Closed Principle (OCP) is formulated as follows: software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.

This means that:

  1. Open for extension: The behavior of a module can be extended without changing its source code. New functionality can be added.
  2. Closed for modification: After development and testing of a class, its interface and implementation should not be changed to add new features. Changes can lead to errors in existing parts of the system.

OCP is often achieved through the use of abstractions (interfaces, abstract classes) and polymorphism. Instead of direct dependence on a specific implementation, a module depends on an abstraction. New functionality is added by creating a new implementation of this abstraction, not by modifying existing classes.

Example: Before:

class ReportGenerator {
    func generateReport(type: String) -> Data {
        if type == "CSV" {
            // Logic for creating CSV
            return Data() // Returning dummy data
        } else if type == "PDF" {
            // Logic for creating PDF
            return Data() // Returning dummy data
        }
        return Data()
    }
}

In this case, to add a new report format (e.g., JSON), the existing generateReport method needs to be modified, which violates OCP.

After (with OCP applied):

// Abstraction
protocol ReportFormatter {
    func format(data: Any) -> Data
}

// Concrete implementations
class CSVReportFormatter: ReportFormatter {
    func format(data: Any) -> Data {
        // Logic for creating CSV
        return Data() // Returning dummy data
    }
}

class PDFReportFormatter: ReportFormatter {
    func format(data: Any) -> Data {
        // Logic for creating PDF
        return Data() // Returning dummy data
    }
}

class ReportGenerator {
    private let formatter: ReportFormatter

    init(formatter: ReportFormatter) {
        self.formatter = formatter
    }

    func generateReport(data: Any) -> Data {
        return formatter.format(data: data)
    }
}

// Usage:
// For CSV
// let csvFormatter = CSVReportFormatter()
// let csvGenerator = ReportGenerator(formatter: csvFormatter)
// csvGenerator.generateReport(data: someData)

// For PDF
// let pdfFormatter = PDFReportFormatter()
// let pdfGenerator = ReportGenerator(formatter: pdfFormatter)
// pdfGenerator.generateReport(data: someData)

// To add JSON: create JSONReportFormatter implementing ReportFormatter

Now, to add a new report format, it is enough to create a new class implementing the ReportFormatter protocol. The existing ReportGenerator does not need to be changed.