Chief Architect's Guide to Implementing the Strategy Pattern in a Travel Booking Platform
Manjeet Singh
Senior Developer with 5 years of experience in full-stack development using React.js, Node.js, Python, and Django. Skilled in building scalable web applications and leading teams.
As the chief architect at a rapidly growing travel booking platform, you're in charge of designing the navigation feature for the app. Imagine you're working on a platform like Rapido, Uber, or Ola. Initially, the code was structured to use a single class for all path-generating tasks across different modes of transport. This approach seemed efficient at first but soon led to several issues.
Problems with the Initial Design
The Solution: Strategy Pattern
To address these issues and enhance the code's maintainability and scalability, the Strategy Pattern can be implemented. This pattern belongs to the Behavioral design family and is defined as follows:
"The Strategy Pattern allows you to define a family of algorithms, encapsulate each one in a separate class, and make them interchangeable. This lets the algorithm vary independently from the clients that use it."
Key Components of the Strategy Pattern:
Applying the Strategy Pattern to Navigation
Using the Strategy Pattern, we can elegantly solve the path navigation problem. We can create a TransportStrategy interface and define separate concrete classes for each type of transport. The client (e.g., TransportationToAirport) then only needs one instance of the interface, automatically delegating the choice of the required transport type based on supplied parameters, such as Bus, Car, or Taxi.
Advantages of the Strategy Pattern:
Improvements Achieved with Strategy Pattern
I guess these are way too many advantages to ignore . And I guess you too are excited to code this naughty dirty problem on your code editor. So Lets jump into it.
Implementing the Strategy Pattern in Python: A Step-by-Step Guide
Before jumping into the code lets first look at the code which earlier developers wrote initially for the project.
The above code will lead to all the bad things which are mentioned in the article at start.
领英推荐
Now the steps which we need to follow to spot and apply the Strategy pattern on the above code are:-
1. Identify the Algorithm Prone to Changes
The algorithm here involves finding the time required for different modes of transport (walk, bus, taxi). The Customer class currently uses conditional logic to determine which transport's time-finding method to call.
2. Declare the Strategy Interface
Define a common interface for all transport strategies. This interface will declare the method find_time() that each transport mode will implement.
3. Extract Algorithms into Their Own Classes
Each transport mode will now be its own class implementing the TransportStrategy interface. For example:
4. Add a Field in the Context Class for the Strategy Object
The Customer class will store a reference to a TransportStrategy object. The class should work with this strategy object via the strategy interface and provide a setter to change the strategy at runtime.
5. Client Associates Context with a Suitable Strategy
The client code should now set the desired transport strategy for the Customer and use it to find the time required.
For reference purposes adding the whole code:-
from abc import ABC, abstractmethod
class TransportStrategy(ABC):
@abstractmethod
def find_time(self) -> int:
pass
class Walk(TransportStrategy):
def find_time(self) -> int:
# Returning a default time for now to avoid complexity
return 25
class Bus(TransportStrategy):
def find_time(self) -> int:
# Returning a default time for now to avoid complexity
return 15
class Taxi(TransportStrategy):
def find_time(self) -> int:
# Returning a default time for now to avoid complexity
return 10
class Customer:
def __init__(self):
self.strategy = None
def set_transport_strategy(self, strategy: TransportStrategy):
self.strategy = strategy
def find_time_required(self) -> int:
if self.strategy is None:
raise ValueError("Transport strategy not set")
return self.strategy.find_time()
# Usage
customer = Customer()
# Customer chooses to walk
customer.set_transport_strategy(Walk())
print(customer.find_time_required()) # Output: 25
# Customer chooses to take the bus
customer.set_transport_strategy(Bus())
print(customer.find_time_required()) # Output: 15
# Customer chooses to take a taxi
customer.set_transport_strategy(Taxi())
print(customer.find_time_required()) # Output: 10
Summary
Implementing the Strategy Pattern makes adding new transport modes easy without altering the Customer class, ensuring a maintainable and flexible system.