Design Patterns That Help Tame Legacy Code (With Python Examples)
Working with legacy code can feel like walking through a minefield. You know something might break, but you’re not sure when—or why. The good news is that design patterns can help.
In this post, I’ll share a few key design patterns that make working with legacy systems safer, cleaner, and more maintainable—using Python code examples.
🧩 1. The Adapter Pattern
Problem: Legacy code doesn't match the interface your modern code expects.
Solution: Wrap the old code in a new interface.
Example:
Let’s say you have a legacy payment gateway:
# legacy_system.py
class LegacyPaymentProcessor:
def make_payment(self, amount):
print(f"[Legacy] Processing payment of ${amount}")
Now, you want to use a modern interface:
# adapter.py
class PaymentInterface:
def pay(self, amount):
raise NotImplementedError
class LegacyAdapter(PaymentInterface):
def __init__(self, legacy_processor):
self.legacy_processor = legacy_processor
def pay(self, amount):
return self.legacy_processor.make_payment(amount)
Usage:
from legacy_system import LegacyPaymentProcessor
from adapter import LegacyAdapter
adapter = LegacyAdapter(LegacyPaymentProcessor())
adapter.pay(100)
✅ You can now use LegacyPaymentProcessor anywhere PaymentInterface is expected.
🏗️ 2. The Facade Pattern
Problem: Legacy subsystems are complex and hard to use.
Solution: Provide a simplified interface to a larger body of code.
Example:
# legacy_subsystem.py
class LegacyAuth:
def check_user(self, username, password):
return username == "admin" and password == "1234"
class LegacyLogger:
def log(self, msg):
print(f"[LOG]: {msg}")
Facade:
class AuthFacade:
def __init__(self):
self.auth = LegacyAuth()
self.logger = LegacyLogger()
def login(self, username, password):
if self.auth.check_user(username, password):
self.logger.log(f"{username} logged in.")
return True
self.logger.log("Invalid login attempt.")
return False
✅ Consumers don’t need to deal with the legacy details.
🧪 3. The Decorator Pattern
Problem: You want to add features without changing legacy code.
Solution: Wrap the legacy object to extend behavior dynamically.
Example:
class LegacyReporter:
def report(self):
print("Generating basic report...")
class TimestampedReporter:
def __init__(self, wrapped):
self.wrapped = wrapped
def report(self):
from datetime import datetime
print(f"Report generated at: {datetime.now()}")
self.wrapped.report()
Usage:
reporter = TimestampedReporter(LegacyReporter())
reporter.report()
✅ Legacy functionality extended without touching the original class.
🧰 4. The Strategy Pattern
Problem: You want to change algorithms used by legacy code without modifying it.
Solution: Inject behavior at runtime.
Example:
class LegacySorter:
def sort(self, data):
return sorted(data) # default
# New strategy
class ReverseSortStrategy:
def sort(self, data):
return sorted(data, reverse=True)
# Updated to accept strategy
class SorterContext:
def __init__(self, strategy):
self.strategy = strategy
def sort(self, data):
return self.strategy.sort(data)
Usage:
sorter = SorterContext(ReverseSortStrategy())
print(sorter.sort([5, 1, 4, 2]))
✅ Clean separation of algorithms for flexible extension.
🚦 5. The Proxy Pattern
Problem: You need to add access control, caching, or logging to legacy classes.
Solution: Create a stand-in object that controls access to the real one.
Example:
class LegacyDatabase:
def query(self, sql):
print(f"Executing SQL: {sql}")
return f"Results for: {sql}"
class LoggingProxy:
def __init__(self, db):
self.db = db
def query(self, sql):
print(f"[LOG] About to query: {sql}")
return self.db.query(sql)
✅ Seamless control over legacy components.
✨ Wrapping Up
Design patterns are not just academic tools—they’re powerful allies when refactoring or integrating legacy code. With Python’s dynamic capabilities, implementing these patterns becomes even more fluid and expressive.
When working with legacy systems, remember:
- Wrap, don’t rewrite (yet).
- Isolate risky code behind interfaces.
- Test as you refactor.
- Make your intentions clear with patterns.
Get in Touch with us
Related Posts
- Fine-Tuning 与 Prompt Engineering 有什么区别? —— 给中国企业的 AI 应用实战指南
- Fine-Tuning vs Prompt Engineering Explained
- 精准灌溉(Precision Irrigation)入门
- Introduction to Precision Irrigation
- 物联网传感器并不是智慧农业的核心——真正的挑战是“数据整合
- IoT Sensors Are Overrated — Data Integration Is the Real Challenge
- React / React Native 移动应用开发服务提案书(面向中国市场)
- Mobile App Development Using React & React Native
- 面向中国市场的 AI 垂直整合(AI Vertical Integration):帮助企业全面升级为高效率、数据驱动的智能组织
- AI Vertical Integration for Organizations
- 中国企业:2025 年 AI 落地的分步骤实用指南
- How Organizations Can Adopt AI Step-by-Step — Practical Guide for 2025
- 为什么中国企业正在加速采用「AI驱动的EV车队管理系统」
- EV Fleet Management SaaS with AI Optimization: The New Operating System for Modern Fleet Businesses
- 正在改变中国制造业的 7 大机器学习(Machine Learning)系统应用场景
- 7 Real-World Machine Learning System Use Cases Transforming Businesses & Factories
- LSTM洪水与水位预测:推动中国智慧水利和城市防汛的新一代AI技术
- Using LSTM for Flood Water-Level Prediction: How Deep Learning Helps Cities Respond Faster
- 用 AI 和自动化打造企业的降本增效体系(中国企业可操作指南)
- The Technical Blueprint Behind Custom Software and AI for Singapore Businesses













