Excerpt from the retail design-pattern refactoring
# Snippet 1: Cart Component
# Refactored from Singleton pattern to Repository pattern
# Carts are now stored separately by cart_id so each user can have their own cart instead of sharing one cart across the entire application.
class Cart:
# cart_id keeps each customer's cart separate.
def __init__(self, cart_id):
self.cart_id = cart_id
self.items = []
# Same add item behavior as the original code.
def add_item(self, item, quantity):
self.items.append((item, quantity))
print(f"Added {quantity} {item}(s) to cart.")
class CartRepository:
# Repository stores Cart objects by cart_id.
def __init__(self):
self._carts = {}
# Return an existing cart or create one if it does not exist.
def get_cart(self, cart_id):
if cart_id not in self._carts:
self._carts[cart_id] = Cart(cart_id)
return self._carts[cart_id]
# Snippet 2: Payment Component
# Refactored from Factory pattern to Strategy pattern.
# The original code used PaymentProcessorFactory and if/elif checks to pick a processor.
# This version lets the calling code pass in the payment strategy instead.
# New payment methods can be added as new strategy classes instead of more if/elif logic.
# Base strategy abstraction for payment methods.
class PaymentStrategy:
def process_payment(self, amount):
raise NotImplementedError("Each payment strategy must define process_payment().")
# Handles credit card payments.
class CreditCardPaymentStrategy(PaymentStrategy):
def process_payment(self, amount):
print(f"Processing {amount} via Credit Card.")
# Handles PayPal payments.
class PayPalPaymentStrategy(PaymentStrategy):
def process_payment(self, amount):
print(f"Processing {amount} via PayPal.")
class PaymentProcessor:
def __init__(self, strategy):
self.strategy = strategyProject objective
Demonstrate how creational, structural, and behavioral patterns organize object creation, compatibility, workflow simplification, and shared application state.
What I produced
- Identified the Singleton pattern in a shared shopping-cart component.
- Identified the Factory pattern in payment-processor creation.
- Analyzed additional pattern examples and documented the criteria used to recognize each one.
- Modified Python code, created UML class diagrams, and compared behavior before and after changes.
Key decisions
- Use Singleton only where one shared state is actually required.
- Separate payment-object creation from the code that consumes payment processors.
- Use adapters and facades to isolate incompatible interfaces and simplify client code.
- Keep pattern selection tied to a specific design problem rather than adding patterns for their own sake.
4+ patternsCreational and structural designs
Before / afterOriginal and modified code compared
UML modelsClass relationships documented
Validation and analysis
- Executed modified code examples and compared outputs.
- Used UML to verify class responsibilities and relationships.
- Recorded repository history to separate original and modified versions.