SOLID Principles

Example 2: Using Interfaces
Interfaces can also be used to adhere to the Open/Closed Principle. Consider the following example:

Violating OCP

public class Invoice
{
    public void GenerateInvoice()
    {
        // Generate invoice logic
    }

    public void PrintInvoice()
    {
        // Print invoice logic
    }
}

In this example, if you need to add functionality to send the invoice by email, you would need to modify the Invoice class.


public class Invoice
{
    public void GenerateInvoice()
    {
        // Generate invoice logic
    }

    public void PrintInvoice()
    {
        // Print invoice logic
    }
}

In this example, if you need to add functionality to send the invoice by email, you would need to modify the Invoice class.


public interface IInvoiceAction
{
    void Execute(Invoice invoice);
}

public class PrintInvoice : IInvoiceAction
{
    public void Execute(Invoice invoice)
    {
        // Print invoice logic
    }
}

public class EmailInvoice : IInvoiceAction
{
    public void Execute(Invoice invoice)
    {
        // Email invoice logic
    }
}

public class Invoice
{
    private readonly List _actions;

    public Invoice(List actions)
    {
        _actions = actions;
    }

    public void GenerateInvoice()
    {
        // Generate invoice logic

        foreach (var action in _actions)
        {
            action.Execute(this);
        }
    }
}

In this design, the IInvoiceAction interface defines an Execute method. The Invoice class can perform multiple actions (such as printing or emailing the invoice) by using a list of IInvoiceAction implementations. Adding new actions (like saving to a database) does not require modifying the Invoice class, thus adhering to the Open/Closed Principle.

Conclusion

The Open/Closed Principle is fundamental for creating flexible and maintainable software. By using abstraction, inheritance, and interfaces, you can design systems that allow for extension without modification. This minimizes the risk of introducing new bugs and makes the codebase easier to understand and maintain.