100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Python

Facade and Proxy Patterns

Learn how Facade simplifies access to a complex subsystem and how Proxy controls access to another object via a shared interface.

Design Patterns — Creational & StructuralIntermediate10 min readJul 8, 2026
Analogies

Introduction

Facade and Proxy round out the core set of Structural design patterns. Facade provides a simplified, unified interface to a set of interfaces in a complex subsystem, making the subsystem easier to use. Proxy provides a surrogate or placeholder for another object, implementing the same interface as that object so it can control access to it — for example, adding lazy loading, access control, caching, or logging transparently.

🏏

Cricket analogy: A team manager gives media a single simplified press briefing (Facade) summarizing complex selection decisions, while a substitute fielder (Proxy) stands in for an injured player, following the exact same fielding rules.

Explanation

A subsystem — like a video conversion library, a payment processing stack, or an operating-system API — often exposes many low-level classes and methods that must be called in a precise sequence to accomplish a common task. A Facade sits in front of that subsystem and exposes a small number of high-level methods (e.g., convert_video(file, format)) that internally coordinate the necessary low-level calls. Client code depends only on the Facade, not on the subsystem's internal classes, which reduces coupling and makes the subsystem easier to swap out or refactor later.

🏏

Cricket analogy: A DRS review system exposes one button 'Review' to the umpire, internally coordinating ball-tracking, snickometer, and hotspot technologies without the umpire needing to know how each one works.

Proxy, by contrast, implements the exact same interface as the object it stands in for (the 'real subject'), so client code can use a proxy interchangeably with the real object without knowing the difference. Common proxy variants include: a virtual proxy that defers creating an expensive object until it's actually needed (lazy initialization), a protection proxy that checks permissions before delegating calls, and a caching proxy that stores results of expensive calls. The defining trait is that the proxy controls access to the real subject while honoring the same contract.

🏏

Cricket analogy: A twelfth man fielding substitute follows the exact same fielding rules as the injured player (same interface), and a stand-in only enters when actually needed, mirroring lazy initialization of a virtual proxy.

Example

python
from abc import ABC, abstractmethod

# --- Facade: simplify a complex subsystem ---
class CPU:
    def freeze(self): print("CPU: freeze")
    def jump(self, addr): print(f"CPU: jump to {addr}")
    def execute(self): print("CPU: execute")

class Memory:
    def load(self, addr, data): print(f"Memory: load '{data}' at {addr}")

class HardDrive:
    def read(self, sector, size): return f"boot-data(sector={sector}, size={size})"

class ComputerFacade:
    def __init__(self):
        self._cpu = CPU()
        self._memory = Memory()
        self._hard_drive = HardDrive()

    def start(self):
        self._cpu.freeze()
        boot_data = self._hard_drive.read(sector=0, size=1024)
        self._memory.load(addr=0, data=boot_data)
        self._cpu.jump(addr=0)
        self._cpu.execute()


# --- Proxy: control access via the same interface as the real subject ---
class Image(ABC):
    @abstractmethod
    def display(self):
        ...

class RealImage(Image):
    def __init__(self, filename):
        self._filename = filename
        self._load_from_disk()  # expensive

    def _load_from_disk(self):
        print(f"Loading {self._filename} from disk (expensive)")

    def display(self):
        print(f"Displaying {self._filename}")

class ImageProxy(Image):
    def __init__(self, filename):
        self._filename = filename
        self._real_image = None  # not loaded yet

    def display(self):
        if self._real_image is None:
            self._real_image = RealImage(self._filename)  # lazy load
        self._real_image.display()


if __name__ == "__main__":
    ComputerFacade().start()

    image = ImageProxy("vacation.jpg")
    print("Proxy created, image not loaded yet")
    image.display()  # loads and displays now

Analysis

ComputerFacade.start() hides the precise sequence of freeze, read, load, jump, and execute calls behind a single method. Client code calls ComputerFacade().start() without needing to know that a CPU, Memory, and HardDrive even exist, let alone the order operations must happen in. In the Proxy example, ImageProxy implements the same Image interface as RealImage, so client code treats image.display() identically whether it's a proxy or the real thing — but the proxy defers the expensive _load_from_disk() work until display() is actually called, illustrated by the 'Proxy created, image not loaded yet' message printing before any loading happens.

🏏

Cricket analogy: A team analyst's single 'match_summary()' report hides the complex sequence of ball-by-ball data collection, wagon-wheel plotting, and partnership analysis that normally requires several separate specialist tools.

The distinction from Adapter is important: Adapter translates between two different interfaces, while Proxy implements the identical interface as the object it represents — no translation occurs, only access control or added indirection. The distinction from Decorator is subtler: both wrap an object behind the same interface, but Decorator's purpose is to add or stack new behavior/responsibilities, whereas Proxy's purpose is to control or manage access to the underlying object (lazy loading, security checks, caching) — the object's core behavior itself is not meant to change.

🏏

Cricket analogy: A translator interpreting a foreign coach's instructions to local players is like Adapter (translating interfaces), whereas a substitute fielder who plays under identical rules as the starter is like Proxy (no translation, just access control).

Key Takeaways

  • Facade provides a single, simplified interface over a complex subsystem of classes.
  • Facade reduces client coupling to subsystem internals, making the subsystem easier to use and refactor.
  • Proxy implements the same interface as a real subject and controls access to it.
  • Common proxy types: virtual (lazy loading), protection (access control), and caching proxies.
  • Proxy differs from Adapter (which translates interfaces) and from Decorator (which adds behavior rather than controlling access).

Practice what you learned

Was this page helpful?

Topics covered

#Python#SoftwareEngineeringStudyNotes#SoftwareEngineering#FacadeAndProxyPatterns#Facade#Proxy#Patterns#Explanation#StudyNotes#SkillVeris