DEV Community

Harsh Mange
Harsh Mange

Posted on • Originally published at harshmange.hashnode.dev on

What is Open-Closed Principle?

Introduction

The Open-Closed Principle is a fundamental principle in software engineering, which states that software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. This means that the behaviour of the software should be easily extensible without modifying the existing code.

In this blog post, we will explain the Open-Closed design pattern in detail, including its benefits, components, and a real-world example.

Benefits

  1. Increased Maintainability: With Open-Closed design pattern, new functionality can be added without changing the existing code. This reduces the risk of introducing new bugs into the codebase and makes it easier to maintain.

  2. Flexibility: The Open-Closed principle enables developers to add new features to the codebase without affecting the existing code. This allows for a more flexible and adaptable software system.

  3. Reusability: Open-Closed design pattern promotes the reuse of existing code. By extending existing functionality, developers can create new features that can be reused in other parts of the system.

Components

The Open-Closed design pattern consists of two main components:

  1. Abstract Base Class: The Abstract Base Class provides a base implementation for a set of related classes. It defines a common interface and provides default behaviour for the related classes.

  2. Concrete Implementations: Concrete Implementations are classes that implement the Abstract Base Class. They provide specific behaviour that extends the base implementation.

Structure

+----------------+ +----------------------+
| Client | | PaymentProcessor |
+----------------+ +----------------------+
| | | + processPayment() |
| + makePayment()|<------------| |
| | | |
+----------------+ +----------------------+
                                            /\
                                            |
                                            |
                                 +---------------------+
                                 | |
                      +---------------------+ +--------------------+
                      | CreditCardProcessor | | PayPalProcessor |
                      +---------------------+ +--------------------+
                      | + processPayment() | | + processPayment() |
                      | | | |
                      +---------------------+ +--------------------+

Enter fullscreen mode Exit fullscreen mode

Example

Let's consider an example of a payment processing system that accepts different payment methods such as credit cards, PayPal, and wire transfers. We want to implement a payment system that can easily add new payment methods without modifying the existing code. We can use the Open-Closed design pattern to achieve this.

First, we create an abstract base class, PaymentProcessor, that provides a common interface for all payment methods. This base class has a method called processPayment that takes the payment amount as input and returns a boolean value indicating whether the payment was successful or not.

public abstract class PaymentProcessor {
    public abstract boolean processPayment(double amount);
}

Enter fullscreen mode Exit fullscreen mode

Next, we create concrete implementations of the PaymentProcessor class for different payment methods. For example, we can create a class for credit card payments:

public class CreditCardPaymentProcessor extends PaymentProcessor {
    public boolean processPayment(double amount) {
        // Implement the credit card payment processing logic here
        return true; // Return true if the payment was successful
    }
}

Enter fullscreen mode Exit fullscreen mode

We can create similar classes for other payment methods such as PayPal and wire transfer.

Finally, we create a PaymentProcessorFactory class that creates instances of the PaymentProcessor based on the input parameter:

public class PaymentProcessorFactory {
    public static PaymentProcessor createPaymentProcessor(String paymentMethod) {
        if (paymentMethod.equals("creditcard")) {
            return new CreditCardPaymentProcessor();
        } else if (paymentMethod.equals("paypal")) {
            return new PayPalPaymentProcessor();
        } else if (paymentMethod.equals("wiretransfer")) {
            return new WireTransferPaymentProcessor();
        } else {
            throw new IllegalArgumentException("Invalid payment method");
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Now, we can use the PaymentProcessorFactory to create instances of different payment methods, as shown below:

PaymentProcessor creditCardPaymentProcessor = PaymentProcessorFactory.createPaymentProcessor("creditcard");
creditCardPaymentProcessor.processPayment(100);

PaymentProcessor payPalPaymentProcessor = PaymentProcessorFactory.createPaymentProcessor("paypal");
payPalPaymentProcessor.processPayment(200);

Enter fullscreen mode Exit fullscreen mode

Conclusion

The Open-Closed design pattern is a powerful principle in software engineering that promotes extensibility, maintainability, flexibility, and reusability. By designing software systems that are open for extension

Top comments (0)