Open-Closed Principle

The Power of the Open-Closed Principle

Open-Closed Principle

 

In today’s instalment, we’ll dive deep into the Open-Closed Principle (OCP). It’s the second of the famous SOLID Principles—the O in the SOLID acronym refers to the OCP. As a recap, here is a high-level explanation of the SOLID Principles’ purpose.

 

The OCP is one of my favourite SOLID Principles. It promotes the building of pluggable systems; i.e. systems where we may replace modules and components with counterparts offering similar yet different capabilities. 

The Open-Closed Principle:

A software artefact should be open for extension
but closed to modification. 

 

The beauty of the OCP lies in its simple message: When we want to change the behaviour of our software systems, we would rather write new code than modify existing code.

 

I think this makes a lot of sense. There exists a substantial flaw in the system architecture if every time we want to add a minor extension to the system, we must make significant changes to our existing code. The OCP encourages us to structure systems in such a way that we rarely need to touch existing code—ideally never. That ideal is rarely achievable; there always come times when we must change code. However, at least we can aim for minimal code changes.

The OCP counteracts Software Rigidity. A rigid system is one that is difficult to change. If we follow the OCP and manage to write only new code for a requirement, how does rigidity affect us? It doesn’t—we have sidestepped a code churn snakepit.

 

Pluggable systems are the result of the OCP. In a pluggable system, we can easily unplug existing functionality by plugging in new functionality. 

 

I have found that the OCP is often best explained in terms of violations and how to fix them. Say, we have this code in our application:

  var paypal= new PaypalPaymentGateway(paypalConfig);
  paypal.Pay(paypalCart, creditCard);

If we wanted to use a different payment gateway, Stripe, then we have little choice but to replace the code to suit Stripe:

  var stripe = new StripePaymentGateway(stripeConfig);
  stripe.BasicPay(stripeCreditCard, creditCart);

Since we had to change these calls; we had to modify the existing code. We are not aligned with the OCP.

 

Can we do better? Probably.

 

It would be helpful if we could have a flexible payment gateway reference that could be either a PaypalPaymentGateway or StripePaymentGateway.

It is possible.

 

Firstly, let’s create an interface, IPaymentGateway, which has a Pay() method:

  public interface IPaymentGateway
  {
     void Pay(ShoppingCart cart, CreditCard card);
  }

 

Both the PaypalPaymentGateway and StripePaymentGateway classes implement IPaymentGateway.

Consequently, the code to pay using either of our payment gateways becomes 

  PaymentGateway.Pay(shoppingCart, creditCard); 

where PaymentGateway is a reference of type IPaymentGateway.

 

Conclusion

We have made it so the payment gateway is pluggable into the calling code; this code actually knows nothing about either Paypal or Stripe!

 

To make the software work for yet another payment gateway, say, Braintree, will mean adding new code, a BraintreePaymentGateway gateway class which implements IPaymentGateway.

(For the curious reader, here is a more detailed and dynamic version of this payment gateway example.) 

 

Continue reading about the OCP:   The OCP Looks Into The Future

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply