A Algo3DVerse
O — Open / Closed
SOLID — Principle 2 of 5

Open / Closed
Principle

Software entities should be open for extension, but closed for modification. Add new behaviour by plugging in new code — not by editing existing code.

Bertrand Meyer's principle, popularised by Robert C. Martin: once a module is working and tested, you should be able to extend its behaviour without touching its source. Modifications risk breaking existing functionality; extensions keep it safe.

Watch it extend

The base platform stays locked. Press Add Extension to plug in new discount types without touching the base class.

drag — scroll to zoom

Code example

Discount logic with a switch vs. an extensible interface. Toggle to compare languages.

OCP VIOLATION ? FIX
// ? BAD — must modify DiscountCalculator for every new type
public class DiscountCalculator
{
    public decimal Calculate(Customer c, decimal price)
    {
        if (c.Type == "Gold")   return price * 0.80m;
        if (c.Type == "Silver") return price * 0.90m;
        // Adding "Platinum"? Edit this class. Risk breaking Gold/Silver.
        return price;
    }
}

// ? GOOD — extend by adding new classes, base never changes
public interface IDiscount
{
    decimal Apply(decimal price);
}

public class GoldDiscount : IDiscount
{
    public decimal Apply(decimal p) => p * 0.80m;
}

public class SilverDiscount : IDiscount
{
    public decimal Apply(decimal p) => p * 0.90m;
}

// Adding Platinum? Just add a new class — zero edits to existing code.
public class PlatinumDiscount : IDiscount
{
    public decimal Apply(decimal p) => p * 0.70m;
}

public class DiscountCalculator  // closed for modification
{
    public decimal Calculate(IDiscount d, decimal price) => d.Apply(price);
}
// ? BAD — every new type requires editing calculate()
function calculate(customer, price) {
    if (customer.type === 'gold')   return price * 0.80;
    if (customer.type === 'silver') return price * 0.90;
    return price; // edit this every time
}

// ? GOOD — strategy pattern; base function never changes
class GoldDiscount     { apply(p) { return p * 0.80; } }
class SilverDiscount   { apply(p) { return p * 0.90; } }
class PlatinumDiscount { apply(p) { return p * 0.70; } }

class DiscountCalculator {
    calculate(discount, price) {
        return discount.apply(price); // closed — never changes
    }
}

// Usage — plug in any strategy, no edits required
const calc = new DiscountCalculator();
calc.calculate(new GoldDiscount(), 100);     // 80
calc.calculate(new PlatinumDiscount(), 100); // 70

Key concepts

➕

Open for Extension

plug in — add new

New behaviour can be added by writing new code — a new class, a new strategy, a new plugin — without touching what already works.

🔒

Closed for Modification

stable — tested

Existing, tested code is sealed. Edits risk regressions. Abstractions protect the stable core from change.

🔑

Abstraction

interface — contract

An interface or abstract class defines the contract. Concrete classes implement it. The consumer only knows the contract — never the implementation.

🃏

Strategy Pattern

swap behaviour — inject

Define a family of algorithms behind an interface. Swap them at runtime without changing the context class. A natural consequence of OCP.

→ Single Responsibility SOLID Principles — Algo3DVerse Liskov Substitution ?
Press ? to begin the narration walkthrough.
0 / 8