The Power of the Open/Closed Principle: Building Extensible Python Applications
Introduction
In the world of software development, the SOLID principles serve as a set of guidelines that help developers create robust, maintainable, and scalable software. One of these principles, the Open/Closed Principle (OCP), is crucial in ensuring our code can be easily extended without modifying existing functionality. This principle is key to writing flexible and maintainable code.
Understanding Open/Closed Principle (OCP)
The Open/Closed Principle states that software entities (such as classes, modules, and functions) should be open for extension but closed for modification. In simpler terms, you should be able to add new functionality to your code without changing the existing code.
Adhering to OCP ensures that existing code remains untouched when new features or functionalities are added. This reduces the risk of introducing bugs and makes the system more stable and easier to maintain.
What does openness and closeness mean?
Real-Life Example: Order Processing System
For example code, follow this repository — https://github.com/fermions75/SOLID-Principles
Violating OCP
In this example, we have an order processing system where we need to calculate the shipping cost based on the shipping method. Initially, we only supported standard shipping, but later, we added support for express shipping.
class Order:
def __init__(self, items, shipping_method):
self.items = items
self.shipping_method = shipping_method
class ShippingCalculator:
def calculate(self, order):
if order.shipping_method == 'standard':
return self.calculate_standard(order)
elif order.shipping_method == 'express':
return self.calculate_express(order)
def calculate_standard(self, order):
return sum(item['price'] for item in order.items) * 0.1
def calculate_express(self, order):
return sum(item['price'] for item in order.items) * 0.2
In this example, the ShippingCalculator class must be modified whenever a new shipping method is added. This violates the Open/Closed Principle.
Adhering to OCP
Using polymorphism, let’s refactor the code to adhere to the Open/Closed Principle.
class Order:
def __init__(self, items, shipping_method: ShippingMethod):
self.items = items
self.shipping_method = shipping_method
class StandardShipping(ShippingMethod):
def calculate(self, order: Order):
return sum(item['price'] for item in order.items) * 0.1
class ExpressShipping(ShippingMethod):
def calculate(self, order: Order):
return sum(item['price'] for item in order.items) * 0.2
class ShippingCalculator:
def calculate(self, order: Order):
return order.shipping_method.calculate(order)
# Usage
standard_shipping = StandardShipping()
order = Order(items=[{'price': 100}, {'price': 200}], shipping_method=standard_shipping)
calculator = ShippingCalculator()
print(calculator.calculate(order)) # Output: 30.0
express_shipping = ExpressShipping()
order_express = Order(items=[{'price': 100}, {'price': 200}], shipping_method=express_shipping)
print(calculator.calculate(order_express)) # Output: 60.0
In this refactored example:
- The ShippingMethod class defines a common interface for all shipping methods.
- The StandardShipping and ExpressShipping classes implement the ShippingMethod interface.
- The ShippingCalculator class calculates the shipping cost using the shipping method provided in the order.
Adhering to the Open/Closed Principle can add new shipping methods (e.g., OvernightShipping, InternationalShipping) without modifying the existing ShippingCalculator class. This makes the system more extensible and maintainable.
Conclusion
Applying the Open/Closed Principle helps in creating flexible and maintainable systems. We can add new features and functionalities without altering existing code by designing classes and modules that are open for extension but closed for modification. This approach reduces the risk of introducing bugs and makes the codebase more robust and scalable. Embracing OCP, along with other SOLID principles, can significantly improve the quality of your software projects.
For example code, follow this repository — https://github.com/fermions75/SOLID-Principles