Bird
Raised Fist0
LLDsystem_design~15 mins

Open/Closed Principle in LLD - Deep Dive

Choose your learning style10 modes available
Overview - Open/Closed Principle
What is it?
The Open/Closed Principle is a design guideline that says software entities like classes, modules, or functions should be open for extension but closed for modification. This means you can add new features without changing existing code. It helps keep software stable and easier to maintain.
Why it matters
Without this principle, every time you add a new feature, you risk breaking existing code. This leads to bugs, longer development times, and frustrated users. Following it makes software more reliable and adaptable to change, which is crucial in real-world projects where requirements evolve.
Where it fits
Before learning this, you should understand basic programming concepts like classes and functions. After this, you can explore other design principles like Single Responsibility Principle and Dependency Inversion Principle to build clean, maintainable systems.
Mental Model
Core Idea
Design software so you can add new features without changing existing code.
Think of it like...
It's like building a LEGO set where you can add new blocks without breaking apart the existing structure.
┌─────────────────────────────┐
│ Existing Code (Closed)       │
│ ┌─────────────────────────┐ │
│ │ Extension Points (Open) │ │
│ └─────────────────────────┘ │
└─────────────────────────────┘
          ↑
          │
    Add new features here
    without changing above
Build-Up - 6 Steps
1
FoundationUnderstanding Software Change
🤔
Concept: Software often needs new features, but changing existing code can cause bugs.
When developers add new features by modifying existing code, they risk introducing errors. This makes software fragile and hard to maintain over time.
Result
Recognizing that changing code frequently leads to problems sets the stage for better design.
Understanding that change is risky motivates designing software that minimizes modifications.
2
FoundationWhat Open/Closed Means Simply
🤔
Concept: Open means you can add new things; closed means you don't change what already works.
Imagine a book where you can add new chapters without rewriting old ones. Similarly, software should allow adding new features without changing existing code.
Result
You grasp the basic idea that software should be extendable without being altered.
Knowing this simple meaning helps you spot when code violates the principle.
3
IntermediateUsing Abstraction for Extension
🤔Before reading on: do you think adding new features requires changing existing classes or creating new ones that fit existing interfaces? Commit to your answer.
Concept: Abstraction lets you add new behaviors by creating new classes that follow existing interfaces.
By defining interfaces or abstract classes, you can write new classes that add features without touching old code. For example, a payment system can add new payment methods by implementing a common interface.
Result
You can extend functionality by adding new classes, keeping old code untouched.
Understanding abstraction is key to applying the Open/Closed Principle effectively.
4
IntermediatePolymorphism Enables Flexibility
🤔Before reading on: do you think polymorphism helps in adding new features without modifying existing code? Commit to yes or no.
Concept: Polymorphism allows objects to be treated as instances of their interface, enabling new behaviors to plug in seamlessly.
When code uses interfaces or base classes, it can work with any new subclass without changes. This lets you add new behaviors by creating new subclasses.
Result
Your system can handle new feature types dynamically without code changes.
Knowing how polymorphism supports extension without modification deepens your design skills.
5
AdvancedApplying Open/Closed in Real Systems
🤔Before reading on: do you think following Open/Closed Principle always makes code simpler? Commit to yes or no.
Concept: In real projects, Open/Closed Principle guides structuring code with plugins, strategies, or configuration to add features safely.
For example, a logging system might support new log formats by adding new classes without changing core code. This often involves design patterns like Strategy or Decorator.
Result
You see how Open/Closed Principle shapes maintainable, scalable software architectures.
Understanding practical patterns helps you apply the principle without overcomplicating code.
6
ExpertBalancing Open/Closed with Complexity
🤔Before reading on: do you think strictly following Open/Closed Principle can sometimes lead to unnecessary complexity? Commit to yes or no.
Concept: While Open/Closed Principle improves flexibility, overusing abstractions can make code harder to understand and maintain.
Experts balance extension and simplicity by applying the principle where it adds real value, avoiding premature abstraction. They also use tools like feature toggles or modular design.
Result
You learn to apply the principle wisely, avoiding common pitfalls of over-engineering.
Knowing when to apply Open/Closed Principle prevents creating overly complex systems that are hard to maintain.
Under the Hood
The principle works by separating stable code from changeable parts using interfaces or abstract classes. The stable code depends on abstractions, not concrete implementations. New features come as new implementations plugged into these abstractions, so existing code remains untouched.
Why designed this way?
It was created to reduce bugs and maintenance costs caused by changing working code. Early software suffered from fragile designs where small changes broke many parts. This principle encourages designs that isolate change, making software more robust and adaptable.
┌───────────────┐      ┌───────────────┐
│ Stable Code   │─────▶│ Interface /   │
│ (Closed)      │      │ Abstract Base │
└───────────────┘      └───────────────┘
                             ▲
                             │
           ┌─────────────┬─────────────┬─────────────┐
           │             │             │             │
     ┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐
     │Feature A│   │Feature B│   │Feature C│   │Feature N│
     └─────────┘   └─────────┘   └─────────┘   └─────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does Open/Closed Principle mean never changing any code after first writing it? Commit to yes or no.
Common Belief:Open/Closed Principle means you should never modify existing code once written.
Tap to reveal reality
Reality:It means you should avoid changing existing code to add features, but bug fixes or improvements may still require changes.
Why it matters:Believing you must never change code can lead to ignoring necessary fixes or improvements, harming software quality.
Quick: Does applying Open/Closed Principle always make code simpler? Commit to yes or no.
Common Belief:Following Open/Closed Principle always simplifies code and design.
Tap to reveal reality
Reality:Sometimes it adds layers of abstraction that increase complexity if applied without care.
Why it matters:Misapplying the principle can create confusing code that is hard to understand and maintain.
Quick: Is inheritance the only way to follow Open/Closed Principle? Commit to yes or no.
Common Belief:You must use inheritance to extend behavior and follow Open/Closed Principle.
Tap to reveal reality
Reality:Composition and delegation are often better ways to extend behavior without modifying code.
Why it matters:Relying only on inheritance can cause rigid designs and tight coupling.
Quick: Does Open/Closed Principle mean you should avoid adding new code? Commit to yes or no.
Common Belief:Open/Closed Principle discourages adding new code to avoid changes.
Tap to reveal reality
Reality:It encourages adding new code (extensions) rather than changing existing code.
Why it matters:Misunderstanding this leads to fear of adding features, blocking progress.
Expert Zone
1
Applying Open/Closed Principle often requires careful interface design to avoid frequent changes to abstractions themselves.
2
Balancing between too many small extensions and too few large ones is key to maintainable design.
3
Using feature toggles or configuration can complement Open/Closed Principle by enabling runtime extension without code changes.
When NOT to use
Avoid strict Open/Closed Principle in small or simple projects where added abstraction overhead outweighs benefits. Instead, prefer straightforward code. Also, when requirements are stable and unlikely to change, simpler designs are better.
Production Patterns
Common patterns include Strategy, Decorator, and Plugin architectures that allow adding new behaviors by creating new classes or modules without modifying core code.
Connections
Single Responsibility Principle
Builds-on
Understanding that each module should have one reason to change helps create stable abstractions that Open/Closed Principle depends on.
Modular Design
Same pattern
Both promote dividing software into independent parts that can evolve separately, improving maintainability.
Biological Evolution
Analogy in nature
Just like species evolve by adding new traits without rewriting existing DNA, software evolves by extending behavior without changing stable code.
Common Pitfalls
#1Changing existing classes to add new features.
Wrong approach:class PaymentProcessor { void processCreditCard() { ... } void processPaypal() { ... } // Added later by modifying class }
Correct approach:interface PaymentMethod { void processPayment(); } class CreditCardPayment implements PaymentMethod { ... } class PaypalPayment implements PaymentMethod { ... }
Root cause:Not using abstraction to separate stable code from extensions.
#2Creating too many small classes for every tiny feature.
Wrong approach:class FeatureA implements Interface {} class FeatureB implements Interface {} class FeatureC implements Interface {} // Each feature is a separate class even if trivial
Correct approach:Group related features logically and avoid unnecessary abstractions until needed.
Root cause:Misunderstanding that Open/Closed Principle means always creating new classes, leading to over-engineering.
#3Modifying interfaces frequently to add new methods.
Wrong approach:interface Shape { void draw(); void resize(); // Added later breaks existing implementations }
Correct approach:Use interface segregation: split interfaces so changes don't affect all implementations.
Root cause:Not designing stable abstractions upfront.
Key Takeaways
Open/Closed Principle means design software so you can add new features without changing existing code.
Using abstraction and polymorphism allows new behaviors to plug in safely, keeping code stable.
Overusing abstractions can add complexity, so apply the principle wisely where it adds real value.
Misunderstanding the principle can lead to fragile code or over-engineered designs.
Balancing extension and simplicity is key to maintainable, scalable software.

Practice

(1/5)
1. What does the Open/Closed Principle (OCP) primarily encourage in software design?
easy
A. Software entities should be open for extension but closed for modification.
B. Software entities should be open for modification but closed for extension.
C. Software entities should be neither open nor closed for changes.
D. Software entities should always be rewritten for new features.

Solution

  1. Step 1: Understand the definition of OCP

    The Open/Closed Principle states that software components should allow new functionality to be added without changing existing code.
  2. Step 2: Match the principle to the options

    Software entities should be open for extension but closed for modification correctly states that entities should be open for extension (new features) but closed for modification (existing code remains unchanged).
  3. Final Answer:

    Software entities should be open for extension but closed for modification. -> Option A
  4. Quick Check:

    OCP = Open for extension, closed for modification [OK]
Hint: Remember: extend without changing existing code [OK]
Common Mistakes:
  • Confusing 'open for extension' with 'open for modification'
  • Thinking OCP means rewriting code for new features
  • Ignoring the 'closed for modification' part
2. Which of the following code structures best supports the Open/Closed Principle?
easy
A. Using inheritance or interfaces to add new behavior without changing existing code.
B. Hardcoding all features inside one large class.
C. Copying and pasting code to create new features.
D. Modifying existing classes directly to add new features.

Solution

  1. Step 1: Identify structures that allow extension without modification

    Inheritance and interfaces allow new classes to add behavior without changing existing classes.
  2. Step 2: Evaluate options against OCP

    Using inheritance or interfaces to add new behavior without changing existing code uses inheritance/interfaces, which aligns with OCP. Other options involve modifying or duplicating code, violating OCP.
  3. Final Answer:

    Using inheritance or interfaces to add new behavior without changing existing code. -> Option A
  4. Quick Check:

    Inheritance/interfaces = OCP support [OK]
Hint: Choose inheritance or interfaces for extension [OK]
Common Mistakes:
  • Thinking direct modification supports OCP
  • Believing code duplication is acceptable
  • Ignoring design patterns that enable extension
3. Consider this code snippet:
class Shape {
  area() { return 0; }
}

class Rectangle extends Shape {
  constructor(width, height) {
    super();
    this.width = width;
    this.height = height;
  }
  area() { return this.width * this.height; }
}

class Circle extends Shape {
  constructor(radius) {
    super();
    this.radius = radius;
  }
  area() { return Math.PI * this.radius * this.radius; }
}

function totalArea(shapes) {
  return shapes.reduce((sum, shape) => sum + shape.area(), 0);
}

What principle does this design demonstrate?
medium
A. Liskov Substitution Principle by replacing shapes with unrelated classes.
B. Single Responsibility Principle by separating area calculation.
C. Dependency Inversion Principle by depending on concrete classes.
D. Open/Closed Principle by allowing new shapes without modifying totalArea.

Solution

  1. Step 1: Analyze how new shapes are added

    New shape classes (Rectangle, Circle) extend Shape and implement area(). totalArea works without changes.
  2. Step 2: Match design to OCP

    Since totalArea does not change when new shapes are added, the design follows Open/Closed Principle.
  3. Final Answer:

    Open/Closed Principle by allowing new shapes without modifying totalArea. -> Option D
  4. Quick Check:

    Adding shapes without changing totalArea = OCP [OK]
Hint: Look for unchanged code when adding new features [OK]
Common Mistakes:
  • Confusing OCP with other SOLID principles
  • Thinking totalArea must change for new shapes
  • Ignoring inheritance usage
4. Given this code violates the Open/Closed Principle:
class Report {
  generate(type) {
    if (type === 'pdf') {
      // generate PDF
    } else if (type === 'html') {
      // generate HTML
    }
  }
}

What is the best fix to comply with OCP?
medium
A. Add more if-else cases inside generate() for new report types.
B. Create separate classes for each report type implementing a common interface.
C. Remove the generate() method and write report code inline.
D. Use global variables to control report type.

Solution

  1. Step 1: Identify why current code violates OCP

    Adding new report types requires modifying generate() method, breaking OCP.
  2. Step 2: Choose design that allows extension without modification

    Separate classes for each report type implementing a common interface allow adding new types without changing existing code.
  3. Final Answer:

    Create separate classes for each report type implementing a common interface. -> Option B
  4. Quick Check:

    Separate classes = extend without modify [OK]
Hint: Use separate classes, not if-else chains [OK]
Common Mistakes:
  • Adding more if-else blocks inside methods
  • Ignoring interface or inheritance use
  • Using global variables for behavior control
5. You are designing a payment system that must support new payment methods without changing existing code. Which approach best follows the Open/Closed Principle?
hard
A. Rewrite the payment processor each time a new method is added.
B. Add new payment method code inside a large switch statement in the payment processor.
C. Implement a Payment interface and create new classes for each payment method.
D. Use global flags to select payment methods inside one class.

Solution

  1. Step 1: Understand the requirement for extensibility without modification

    The system must allow adding new payment methods without changing existing code.
  2. Step 2: Evaluate design options for OCP compliance

    Implementing a Payment interface and creating new classes for each method allows extension by adding classes, not modifying existing ones.
  3. Final Answer:

    Implement a Payment interface and create new classes for each payment method. -> Option C
  4. Quick Check:

    Interface + new classes = OCP compliance [OK]
Hint: Use interfaces and new classes for new features [OK]
Common Mistakes:
  • Using switch statements that require modification
  • Rewriting existing code repeatedly
  • Using global flags for behavior control
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard