📜

Understanding the Open-Closed Principle

Jan 19, 2025

Notes on Open-Closed Principle (OCP)

Introduction

  • Part of the Solid Principles series.
  • Previous discussion on the Single Responsibility Principle (SRP).
  • Today's focus: Open-Closed Principle (OCP).

Definition of OCP

  • A class should be open for extension but closed for modification.
  • New features or behaviors should be added without altering existing code.

Example: FTS Hotel Management System

  • Recently inaugurated hotel offering initial discounts:
    • Flat $10 discount on every bill initially.
    • Later introduced percentage-based discounts and seasonal discounts.

Initial Implementation of Discounts

  1. Flat Discount Calculation:

    • Created DiscountCalculator class with calculateFlatDiscount method.
    • Method accepts billAmount, subtracts $10 from it.
    • Initially works fine for flat discounts.
  2. Introducing Percentage Discount:

    • Modified DiscountCalculator to accommodate multiple discount types:
    • Added an if condition to check discount type:
      • If flat, subtract $10.
      • If percentage, return 90% of the bill.
    • This leads to complexity and violates OCP:
      • Future changes require modifications to the method, risking bugs and maintenance issues.

Refactoring to Follow OCP

  • Goals:
    • Ensure system is extensible and future-proof.
  • Plan:
    1. Create a base Discount class to define a common structure.
    2. Each discount type will extend this base class.
    3. The DiscountCalculator will work with these classes without knowing specifics.

Implementation Steps

  1. Create Abstract Class: Discount

    • Defines an abstract method applyDiscount(double billAmount).
    • Acts as a blueprint for all discount types.
  2. Implement Flat Discount:

    • Create FlatDiscount class extending Discount.
    • Override applyDiscount: return billAmount - 10.
  3. Implement Percentage Discount:

    • Create PercentageDiscount class extending Discount.
    • Override applyDiscount: return billAmount * 0.9 (10% discount).
  4. Update Discount Calculator:

    • Modify to work with Discount objects directly.
    • Calls discount.applyDiscount(billAmount) without needing if conditions.*

Usage in Main Program

  • Example code using the new structure:
    • Create instances of FlatDiscount and PercentageDiscount.
    • Pass these objects to DiscountCalculator to apply discounts.

Adding New Discount Types

  • Example: Adding a 20% seasonal discount:
    • Create SeasonalDiscount class extending Discount.
    • Override applyDiscount: return billAmount * 0.8 (20% discount).
  • New types can be added without modifying existing code.*

Conclusion

  • The refactored code adheres to the OCP.
  • Class is open for extension and closed for modification.
  • Next topic: Liskov Substitution Principle (LSP) for class hierarchy collaboration.