Facade Pattern in Python with Mock Simplification
This code demonstrates the Facade pattern by hiding complex subsystem interactions behind a simple start/stop interface, and adds a MockFacade for testing failure scenarios.
Python code
51 linesclass SubsystemA:
def operation_a(self):
return "Subsystem A: ready"
class SubsystemB:
def operation_b(self):
return "Subsystem B: ready"
class SubsystemC:
def operation_c(self):
return "Subsystem C: ready"
class Facade:
def __init__(self):
self._a = SubsystemA()
self._b = SubsystemB()
self._c = SubsystemC()
def start(self):
results = [
self._a.operation_a(),
self._b.operation_b(),
self._c.operation_c(),
]
return " | ".join(results)
def stop(self):
return "All subsystems stopped"
class MockFacade(Facade):
def __init__(self, fail=False):
super().__init__()
self._fail = fail
def start(self):
if self._fail:
return "Mock: simulation failure"
return "Mock: " + super().start()
if __name__ == "__main__":
real = Facade()
mock = MockFacade()
mock_fail = MockFacade(fail=True)
print("Real facade:", real.start())
print("Mock facade:", mock.start())
print("Mock failed:", mock_fail.start())
print("Stop:", real.stop())
Output
Real facade: Subsystem A: ready | Subsystem B: ready | Subsystem C: ready
Mock facade: Mock: Subsystem A: ready | Subsystem B: ready | Subsystem C: ready
Mock failed: Mock: simulation failure
Stop: All subsystems stopped
How it works
The Facade class encapsulates the initialization and coordination of three subsystems, exposing a simplified start and stop API. The MockFacade extends the Facade and overrides start to simulate success or failure without touching the real subsystems. This decouples client code from the subsystem internals, making it easier to test or replace complexity. The __main__ block demonstrates both real and mock behavior, showing how the facade hides implementation details.
Common mistakes
- Forgetting to call `super().__init__()` in the mock subclass to initialize subsystems
- Overriding `stop` in MockFacade when not needed, risking inconsistent behavior
- Making the facade too thick by exposing subsystem methods instead of a simplified interface
Variations
- Use a factory function to return either a Facade or MockFacade based on configuration
- Implement MockFacade with dependency injection instead of inheritance for more flexibility
Real-world use cases
- Wrapping multiple microservice clients behind a single API for a mobile app backend.
- Providing a simplified test double for a complex payment gateway in unit tests.
- Hiding intricate legacy system calls behind a clean interface for a new module.
Sponsored
More from System design patterns
- Build a BFF (Backend for Frontend) Mock Aggregator in Python medium
- Builder pattern for mocking complex objects in Python easy
- Circuit Breaker Pattern in Python: Closed, Open, and Half-Open States medium
- Create a Data Helper Class in Python easy
- Domain Driven Design Aggregate Root Example in Python medium
- How to Aggregate Mock API Routes by Method in Python easy
Keep learning
Related tutorials and quizzes for this topic.