Logo

dev-resources.site

for different kinds of informations.

SOLID: Open-Closed Principle (OCP) in C#

Published at
11/12/2024
Categories
solidprinciples
designpatterns
dotnet
csharp
Author
extinctsion
Author
11 person written this
extinctsion
open
SOLID: Open-Closed Principle (OCP) in C#

Introduction

It says, "Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification."

This means that we should be able to add new functionality to an entity without changing its existing code. Adhering to OCP helps make code more maintainable, less error-prone, and adaptable to new requirements.

In this article, we’ll look at how to implement OCP in C#, with practical examples.

Why the Open-Closed Principle?

When code is “open for extension,” it can be easily adapted to add new features without disturbing existing code. However, being “closed for modification” protects the code from unintended side effects that can arise from altering core logic. This approach improves software stability and makes testing and maintenance easier.

Open closed

Let’s take a look at some examples to understand how OCP works and how to implement it in C#.

A Non-OCP-Compliant Example

Imagine we’re building a payment processing system. Here’s a simple class that processes payments based on different payment methods:

Bad Code ❌

public class PaymentProcessor
{
    public void ProcessPayment(string paymentMethod)
    {
        if (paymentMethod == "CreditCard")
        {
            // Process credit card payment
            Console.WriteLine("Processing credit card payment...");
        }
        else if (paymentMethod == "PayPal")
        {
            // Process PayPal payment
            Console.WriteLine("Processing PayPal payment...");
        }
        else if (paymentMethod == "Bitcoin")
        {
            // Process Bitcoin payment
            Console.WriteLine("Processing Bitcoin payment...");
        }
        else
        {
            throw new ArgumentException("Invalid payment method.");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

While this code works, it violates OCP because every time we add a new payment method (like GooglePay or ApplePay), we’ll have to modify the ProcessPayment method. This approach is error-prone and can lead to fragile code as the application grows.

Refactoring to Follow the Open-Closed Principle

To refactor this code to follow the Open-Closed Principle, we can use polymorphism. We’ll create an interface called IPaymentMethod with a ProcessPayment method. Each payment type will have its own class implementing this interface.

Step 1: Define an Interface

We start by defining an IPaymentMethod interface:

public interface IPaymentMethod
{
    void ProcessPayment();
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Implement Concrete Classes for Each Payment Method

Next, we create separate classes for each payment type that implement IPaymentMethod:

public class CreditCardPayment : IPaymentMethod
{
    public void ProcessPayment()
    {
        Console.WriteLine("Processing credit card payment...");
    }
}

public class PayPalPayment : IPaymentMethod
{
    public void ProcessPayment()
    {
        Console.WriteLine("Processing PayPal payment...");
    }
}

public class BitcoinPayment : IPaymentMethod
{
    public void ProcessPayment()
    {
        Console.WriteLine("Processing Bitcoin payment...");
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Modify the PaymentProcessor Class

Now, instead of directly handling the payment types, PaymentProcessor will use the IPaymentMethod interface. This makes the class open for extension but closed for modification.

public class PaymentProcessor
{
    public void ProcessPayment(IPaymentMethod paymentMethod)
    {
        paymentMethod.ProcessPayment();
    }
}
Enter fullscreen mode Exit fullscreen mode

Using the Refactored Code

Let’s see how to use this refactored code:

Good Code âś…

class Program
{
    static void Main()
    {
        PaymentProcessor paymentProcessor = new PaymentProcessor();

        IPaymentMethod creditCardPayment = new CreditCardPayment();
        IPaymentMethod paypalPayment = new PayPalPayment();
        IPaymentMethod bitcoinPayment = new BitcoinPayment();

        paymentProcessor.ProcessPayment(creditCardPayment);
        paymentProcessor.ProcessPayment(paypalPayment);
        paymentProcessor.ProcessPayment(bitcoinPayment);
    }
}
Enter fullscreen mode Exit fullscreen mode

With this structure, adding a new payment type (e.g., GooglePayPayment) only requires creating a new class that implements IPaymentMethod, without modifying PaymentProcessor.

Benefits of Following OCP

  1. Improved Flexibility: New functionality can be added without changing existing code, making the codebase more adaptable.

  2. Reduced Errors: With separate classes for each payment method, errors are less likely to propagate to unrelated parts of the code.

  3. Enhanced Maintainability: Code is easier to understand, and maintenance tasks are more manageable.

  4. Facilitated Testing: Each payment type class can be independently tested, simplifying the testing process.

Conclusion

The Open-Closed Principle encourages designing code that is adaptable to change and resistant to breakage. In this article, we’ve covered how to implement OCP in C# with examples, such as payment processing and logging.
By using interfaces and polymorphism, you can make your code open for extension but closed for modification—leading to a more robust, flexible, and maintainable codebase.

A big thank you to you, mate! For reading and supporting. đź’ś đź’– đź’›

Open closed

Let connect on LinkedIn and checkout my GitHub repos:

solidprinciples Article's
30 articles in total
Favicon
ISP - O Princípio da Segregação de Interface
Favicon
Disadvantages of the Single Responsibility Principle(SRP)
Favicon
Guia: O que Ă© SOLID
Favicon
Interface Segregation Principle (ISP)
Favicon
Dependency Inversion Principle (DIP)
Favicon
Liskov Substitution Principle (LSP)
Favicon
Create your own Logger using Open-closed principle
Favicon
SOLID: Dependency Inversion Principle (DIP) in C#
Favicon
SOLID: Principio de Abierto/Cerrado
Favicon
LSP - O Princípio da Substituição de Liskov
Favicon
SOLID: Principio de Responsabilidad Ăšnica
Favicon
SOLID Principles for React / React Native Development
Favicon
Single Responsibility Principle (SRP)
Favicon
Solid Prensipleri
Favicon
Mastering SOLID Principles in .NET Core: A Path to Clean and Scalable Code
Favicon
OCP - O PrincĂ­pio Aberto/Fechado
Favicon
SRP - O PrincĂ­pio da Responsabilidade Ăšnica
Favicon
SOLID Design Principles
Favicon
Rethinking interfaces in Flutter projects
Favicon
Understanding the SOLID Principles in PHP and How They Improve Code Quality
Favicon
SOLID: The Liskov Substitution Principle (LSP) in C#
Favicon
Is Clean Code really practical?
Favicon
Open/Closed Principle (OCP)
Favicon
Single Responsibility Principle (SRP)
Favicon
Solid Principle in Simple English
Favicon
Why Clean Architecture and SOLID Principles Should Be the Foundation of Your Next Project!
Favicon
Seja um desenvolvedor melhor com S.O.L.I.D.
Favicon
SOLID: Open-Closed Principle (OCP) in C#
Favicon
SOLID Principles Explained in a Simple Way 🛠️✨ with Real-Life Examples
Favicon
Object Oriented Design Balance With Understanding Anti-Single Responsibility Principle

Featured ones: