Skip to content

Facade pattern

Quality Score

Overall Score: 9.8/10 ⭐ Outstanding

  • Technical Accuracy: 34/35
  • Code Quality: 25/25
  • Educational Value: 25/25
  • Documentation: 14/15

Last reviewed: August 18, 2026

The facade pattern is a structural design pattern that provides a simplified interface to a complex subsystem. It allows clients to interact with the subsystem without needing to understand its internal workings. The benefits of this pattern are:

  • Simplified interface: The facade pattern provides an easy, simple and unified interface to a set of library or services, allowing quicker usage of the subsystem.
  • Decoupling: The facade pattern decouples the client code from the complex subsystem, allowing for more flexible and maintainable code.
  • Single Responsibility Principle: The facade pattern allows for the separation of concerns, allowing for a single responsibility for each class.
  • Encapsulation: The facade pattern encapsulates the complexity of the subsystem, allowing for a more modular and maintainable codebase.

The facade pattern is composed of three main components:

Facade

Defines the simplified interface to the complex subsystem. It should hide any internal details, such as data model, connection to database, service calls, etc.

src.advanced.facade_pattern.BookstoreFacade

Facade for managing books and their stock in the bookstore.

Source code in src/advanced/facade_pattern/facade.py
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
class BookstoreFacade:
    """Facade for managing books and their stock in the bookstore."""

    def __init__(
        self,
        book_manager: BookManager,
        inventory_stock: InventoryBookStock,
        isbn_validator: IsbnValidator,
    ) -> None:
        """Initialize the BookstoreFacade with its subsystem collaborators.

        Args:
            book_manager: Subsystem responsible for storing and retrieving
                books.
            inventory_stock: Subsystem responsible for tracking stock levels.
            isbn_validator: Subsystem responsible for validating ISBN numbers.
        """
        self.book_manager = book_manager
        self.inventory_stock = inventory_stock
        self.isbn_validator = isbn_validator

    @classmethod
    def create(cls) -> "BookstoreFacade":
        """Create a facade instance with default subsystem collaborators.

        Convenience factory that wires up fresh instances of every subsystem
        used by the facade. Prefer the regular constructor when you need to
        inject custom or pre-configured subsystems (e.g. in tests).

        Returns:
            A new BookstoreFacade backed by default subsystem instances.
        """
        book_manager = BookManager()
        inventory_stock = InventoryBookStock()
        isbn_validator = IsbnValidator()
        return cls(
            book_manager=book_manager,
            inventory_stock=inventory_stock,
            isbn_validator=isbn_validator,
        )

    def new_book(
        self,
        isbn: str,
        title: str,
        author: str,
        quantity: int,
    ) -> None:
        """Add a book to the bookstore and set its stock level.

        Args:
            isbn: The International Standard Book Number of the book.
            title: The title of the book.
            author: The author of the book.
            quantity: The stock level to set for the book.

        Raises:
            ValueError: If isbn is not a valid ISBN-10 or ISBN-13.
        """
        if not self.isbn_validator.is_valid_isbn(isbn):
            raise ValueError(f"Invalid ISBN: {isbn}")

        book = Book(isbn, title, author)
        self.book_manager.add_book(book)
        self.inventory_stock.set_stock(isbn, quantity)

    def list_books_with_stock(self) -> list[str]:
        """List all books in the bookstore with stock.

        Returns:
            A list of books that have stock available.
        """
        books = self.book_manager.list_books()
        books_with_stock = []
        for book in books:
            if self.inventory_stock.get_stock(book.isbn) > 0:
                books_with_stock.append(book.title)

        return books_with_stock

    def purchase_book(self, isbn: str, quantity: int) -> bool:
        """Purchase a specific quantity of a book.

        Args:
            isbn: The International Standard Book Number of the book.
            quantity: The quantity to purchase.

        Returns:
            True if the purchase was successful (enough stock), False otherwise.
        """
        if self.book_manager.find_book_by_isbn(isbn):
            return self.inventory_stock.purchase_book(isbn, quantity)
        return False

Subsystem

The subsystem is composed of multiple classes that work together to provide the functionality of the subsystem. The subsystem classes should not be aware of the facade, and should not depend on it. The subsystem classes should be designed to work together, and should not be designed to work independently.

src.advanced.facade_pattern.BookManager

Manages a collection of books in the bookstore.

For this example, it uses an in-memory list to store books. In a real-world, it could be any database.

Source code in src/advanced/facade_pattern/facade.py
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
class BookManager:
    """Manages a collection of books in the bookstore.

    For this example, it uses an in-memory list to store books. In a real-world,
    it could be any database.
    """

    def __init__(self) -> None:
        """Initialize the BookManager with an empty list of books."""
        self.books: list[Book] = []

    def add_book(self, book: Book) -> None:
        """Add a book to the collection.

        Args:
            book: The Book instance to be added.
        """
        self.books.append(book)

    def list_books(self) -> list[Book]:
        """List all books in the collection.

        Returns:
            A list of Book instances.
        """
        return self.books

    def find_book_by_isbn(self, isbn: str) -> Book | None:
        """Find a book by its ISBN.

        Args:
            isbn: The International Standard Book Number of the book to find.

        Returns:
            The Book instance if found, otherwise None.
        """
        for book in self.books:
            if book.isbn == isbn:
                return book
        return None

    def remove_book(self, isbn: str) -> bool:
        """Remove a book from the collection by its ISBN.

        Args:
            isbn: The International Standard Book Number of the book to remove.

        Returns:
            True if the book was removed, False otherwise.
        """
        book = self.find_book_by_isbn(isbn)
        if book:
            self.books.remove(book)
            return True
        return False

src.advanced.facade_pattern.InventoryBookStock

Manages the stock levels of books in the bookstore.

In this example, it uses an in-memory dictionary to track stock levels. In a real-world, it could be a external inventory management system.

Source code in src/advanced/facade_pattern/facade.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
class InventoryBookStock:
    """Manages the stock levels of books in the bookstore.

    In this example, it uses an in-memory dictionary to track stock levels. In a
    real-world, it could be a external inventory management system.
    """

    def __init__(self) -> None:
        """Initialize the InventoryBookStock with an empty stock dictionary."""
        self.stock: dict[str, int] = {}

    def set_stock(self, isbn: str, quantity: int) -> None:
        """Set the stock level for a specific book.

        Args:
            isbn: The International Standard Book Number of the book.
            quantity: The stock level to set for the book.
        """
        self.stock[isbn] = quantity

    def get_stock(self, isbn: str) -> int:
        """Get the stock level for a specific book.

        Args:
            isbn: The International Standard Book Number of the book.

        Returns:
            The stock level of the book. Returns 0 if the book is not found.
        """
        return self.stock.get(isbn, 0)

    def purchase_book(self, isbn: str, quantity: int) -> bool:
        """Purchase a specific quantity of a book.

        Args:
            isbn: The International Standard Book Number of the book.
            quantity: The quantity to purchase.

        Returns:
            True if the purchase was successful (enough stock), False otherwise.
        """
        current_stock = self.get_stock(isbn)
        if current_stock >= quantity:
            self.stock[isbn] = current_stock - quantity
            return True
        return False

src.advanced.facade_pattern.IsbnValidator

Validates ISBN numbers for books.

This class provides methods to validate the format of both ISBN-10 and ISBN-13. In a real-world scenario this could be delegated to an external service.

Source code in src/advanced/facade_pattern/facade.py
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
class IsbnValidator:
    """Validates ISBN numbers for books.

    This class provides methods to validate the format of both ISBN-10 and
    ISBN-13. In a real-world scenario this could be delegated to an external
    service.
    """

    @staticmethod
    def is_valid_isbn(isbn: str) -> bool:
        """Validate the given ISBN number (ISBN-10 or ISBN-13).

        Hyphens and spaces are ignored. The check digit is verified against
        the standard checksum for the detected format.

        Args:
            isbn: The International Standard Book Number to validate.

        Returns:
            True if the ISBN is a valid ISBN-10 or ISBN-13, False otherwise.
        """
        if not isbn:
            return False

        normalized = isbn.replace("-", "").replace(" ", "")

        if len(normalized) == ISBN10_LENGTH:
            return IsbnValidator._is_valid_isbn10(normalized)
        if len(normalized) == ISBN13_LENGTH:
            return IsbnValidator._is_valid_isbn13(normalized)
        return False

    @staticmethod
    def _is_valid_isbn10(isbn: str) -> bool:
        """Validate a normalized 10-character ISBN-10 string.

        Args:
            isbn: The normalized ISBN-10 string (no hyphens or spaces).

        Returns:
            True if the checksum is valid, False otherwise.
        """
        if not isbn[:-1].isdigit() or isbn[-1] not in "0123456789X":
            return False
        total = sum(
            (i + 1) * (10 if x == "X" else int(x)) for i, x in enumerate(isbn)
        )
        return total % 11 == 0

    @staticmethod
    def _is_valid_isbn13(isbn: str) -> bool:
        """Validate a normalized 13-character ISBN-13 string.

        Args:
            isbn: The normalized ISBN-13 string (no hyphens or spaces).

        Returns:
            True if the checksum is valid, False otherwise.
        """
        if not isbn.isdigit():
            return False
        total = sum(
            int(x) * (1 if i % 2 == 0 else 3) for i, x in enumerate(isbn)
        )
        return total % 10 == 0

Client

The client is the code that uses the facade to interact with the subsystem. The client should not be aware of the internal workings of the subsystem, and should only interact with the facade. The client should be designed to work with the facade, which is curated to expose only the necessary functionality, avoiding using the complexity to init and manage the subsystem classes.

`python store = BookstoreFacade.create() store.new_book("9788413148465", "Project Hail Mary", "Andy Weir", 5) store.purchase_book("9788413148465", 1) Some good notes to keep in mind when using the facade pattern are:

  • A big facade is a code smell. You can then split it into multiple smaller facades, each with a specific responsibility.
  • Avoid exposing the subsystem classes to the client code. The facade should be the only point of contact for the client code. Create new data models to return from the facade, instead of returning the subsystem classes.
  • to ensure that client code is using the facade, you can use a linter to enforce that the subsystem classes are not used directly, such as import-linter.

Some real-world examples are: complex libraries or frameworks, backend for microservices, services that require multiple steps to perform a task, and systems that require a simplified interface for end-users.