Home >Backend Development >PHP Tutorial >PHP Master | Manage Complexity with the Facade Pattern
<span><span><?php </span></span><span><span>public class User </span></span><span><span>{ </span></span><span> <span>public function borrowBook() { </span></span><span> <span>$bookManager = new Book_Manager(); </span></span><span> <span>$bookManager->returnBooks(); </span></span><span> </span><span> <span>$bookPayments = new Book_Payments(); </span></span><span> <span>if ($bookPayments->hasOverdueBooks()) { </span></span><span> <span>$bookPayments->payBookFines(); </span></span><span> <span>} </span></span><span> </span><span> <span>$bookLibrary = new Book_Library(); </span></span><span> <span>$bookReservations = new Book_Reservations(); </span></span><span> </span><span> <span>$book = $bookLibrary->searchBooks(); </span></span><span> <span>$isAvailable = $bookLibrary->isBookAvailable($book); </span></span><span> <span>$isReserved = $bookReservations->isBookReserved($book); </span></span><span> <span>if ($isAvailable && !isReserved) { </span></span><span> <span>$bookLibrary->locateBook($book); </span></span><span> </span><span> <span>$bookManager->borrowBook($book); </span></span><span> <span>$bookLibrary->updateBookAvailability($book, $status); </span></span><span> <span>} </span></span><span> <span>} </span></span><span><span>}</span></span>You can see the process of borrowing a book is actually a complex process! In this implementation, a user has to interact with four different classes and around ten methods to borrow a book. Assume that each bit of functionality is implemented as a separate screen in the application; can you imagine the effort required for borrowing three books with this system? And the borrower doesn’t need to know about functionality such as checking reservations and updating the status. We certainly have a problem with our implementation.
<span><span><?php </span></span><span><span>class Library_Facade </span></span><span><span>{ </span></span><span> <span>public function returnBooks() { </span></span><span> <span>// previous implementation by calling necessary classes </span></span><span> <span>} </span></span><span> </span><span> <span>public function borrowBooks() { </span></span><span> <span>} </span></span><span> </span><span> <span>public function searchBooks() { </span></span><span> <span>} </span></span><span> </span><span> <span>public function reserveBooks() { </span></span><span> <span>} </span></span><span><span>}</span></span>The user can borrow books by calling the borrowBook() method of the Library_Facade class as shown in the following example:
<span><span><?php </span></span><span><span>class User </span></span><span><span>{ </span></span><span> <span>public function borrowBook() { </span></span><span> <span>$libraryFacade = new Library_Facade(); </span></span><span> <span>$libraryFacade->borrowBook(); </span></span><span> <span>} </span></span><span><span>}</span></span>With this facade-based implementation, the user only talks to the Library_Facade class and has no idea how the functionality is implemented beyond it. A user can directly request any feature from the facade and the facade is responsible for handling the complex process and returning the appropriate information. The Facade pattern adheres to the principle of least knowledge in which each unit should have minimal knowledge about the other units. Even though the low-level functionality is hidden from the user through the facade, the user can still request low-level classes directly when needed. Think about your own projects and where you might find situations where you’ve implemented the Facade pattern without even realizing it.
A facade is an object that provides a simplified interface to a larger body of code, such as a class library. A facade can:Here’s a class diagram of our library example that identifies the components mentioned in the Facade pattern definition.
- make a software library easier to use, understand, and test since the facade has convenient methods for common tasks;
- make the library more readable, for the same reason;
- reduce dependencies of outside code on the inner workings of a library, since most code uses the facade allowing more flexibility in developing a system;
- wrap a poorly designed collection of APIs with a single well-designed API.
<span><span><?php </span></span><span><span>public class User </span></span><span><span>{ </span></span><span> <span>public function borrowBook() { </span></span><span> <span>$bookManager = new Book_Manager(); </span></span><span> <span>$bookManager->returnBooks(); </span></span><span> </span><span> <span>$bookPayments = new Book_Payments(); </span></span><span> <span>if ($bookPayments->hasOverdueBooks()) { </span></span><span> <span>$bookPayments->payBookFines(); </span></span><span> <span>} </span></span><span> </span><span> <span>$bookLibrary = new Book_Library(); </span></span><span> <span>$bookReservations = new Book_Reservations(); </span></span><span> </span><span> <span>$book = $bookLibrary->searchBooks(); </span></span><span> <span>$isAvailable = $bookLibrary->isBookAvailable($book); </span></span><span> <span>$isReserved = $bookReservations->isBookReserved($book); </span></span><span> <span>if ($isAvailable && !isReserved) { </span></span><span> <span>$bookLibrary->locateBook($book); </span></span><span> </span><span> <span>$bookManager->borrowBook($book); </span></span><span> <span>$bookLibrary->updateBookAvailability($book, $status); </span></span><span> <span>} </span></span><span> <span>} </span></span><span><span>}</span></span>As you can see, we call a set of Twitter-specific library methods to implement the desired functionality. A similar approach would be necessary for both LinkedIn and Facebook. The process has already become complex. We’re not developing a Twitter, Facebook, or Linkedin application; we should just validate the credentials and authenticate the user. Our application shouldn’t be worried about the implementation of each of these services. We can solve this problem by using the Opauth library as a facade interface. First we need to specify the login URLs of the desired services in a common format to be identified by the Opauth plugin. Consider the following code for implementing the authentication process.
<span><span><?php </span></span><span><span>class Library_Facade </span></span><span><span>{ </span></span><span> <span>public function returnBooks() { </span></span><span> <span>// previous implementation by calling necessary classes </span></span><span> <span>} </span></span><span> </span><span> <span>public function borrowBooks() { </span></span><span> <span>} </span></span><span> </span><span> <span>public function searchBooks() { </span></span><span> <span>} </span></span><span> </span><span> <span>public function reserveBooks() { </span></span><span> <span>} </span></span><span><span>}</span></span>Once the login link is requested, Opauth identifies the requested service from the URL and initializes the library to redirect the user for authentication. Our application now only needs to create the login links and call the initialize method. All of the complex authentication stuff is handled behind-the-scenes using the respective libraries for each service. This can be considered a perfect example for effectively using the Facade pattern.
<span><span><?php </span></span><span><span>public class User </span></span><span><span>{ </span></span><span> <span>public function borrowBook() { </span></span><span> <span>$bookManager = new Book_Manager(); </span></span><span> <span>$bookManager->returnBooks(); </span></span><span> </span><span> <span>$bookPayments = new Book_Payments(); </span></span><span> <span>if ($bookPayments->hasOverdueBooks()) { </span></span><span> <span>$bookPayments->payBookFines(); </span></span><span> <span>} </span></span><span> </span><span> <span>$bookLibrary = new Book_Library(); </span></span><span> <span>$bookReservations = new Book_Reservations(); </span></span><span> </span><span> <span>$book = $bookLibrary->searchBooks(); </span></span><span> <span>$isAvailable = $bookLibrary->isBookAvailable($book); </span></span><span> <span>$isReserved = $bookReservations->isBookReserved($book); </span></span><span> <span>if ($isAvailable && !isReserved) { </span></span><span> <span>$bookLibrary->locateBook($book); </span></span><span> </span><span> <span>$bookManager->borrowBook($book); </span></span><span> <span>$bookLibrary->updateBookAvailability($book, $status); </span></span><span> <span>} </span></span><span> <span>} </span></span><span><span>}</span></span>Only the necessary code is shown; the complete source code for the update_metadata() function is available in meta.php file inside the wp-includes directory. But you can see all of the validation, filtering, and database updates are implemented here and only the facade interface has knowledge about the details.
The Facade Pattern is a structural design pattern that provides a simplified interface to a complex system of classes, library or framework. It hides the complexities of the system and provides an interface to the client from where the client can access the system. This pattern involves a single class which provides simplified methods required by the client and delegates calls to methods of existing system classes.
The Facade Pattern improves code readability and usability by providing a simple interface to a complex subsystem. Instead of making the client deal with several subsystem classes directly, the facade encapsulates the subsystems with a unified interface. This reduces the learning curve necessary to understand the subsystem and makes the subsystem easier to use and manage.
A real-world example of the Facade Pattern is the use of a computer. When you turn on your computer, you don’t need to understand how the internal components work together to boot up the system. You simply press the power button (the facade) and the complex process happens behind the scenes.
The main advantage of the Facade Pattern is that it simplifies the interface to a complex subsystem, making it easier for the client to use. It also promotes decoupling between subsystems and their clients, which can make the system more modular and easier to maintain. However, a potential disadvantage is that the Facade Pattern can become a bottleneck if too much functionality is put into the facade. It can also hide useful features of the subsystem from the client.
Unlike other structural design patterns like the Adapter or Decorator patterns, which are used to add or change the behavior of individual objects, the Facade Pattern is used to simplify a complex system of classes. It provides a simplified interface to a complex subsystem, hiding the intricacies of the subsystem from the client.
Yes, the Facade Pattern can be used in conjunction with other design patterns. For example, it can be used with the Singleton Pattern to ensure that only one instance of the facade is created. It can also be used with the Abstract Factory Pattern to provide a simple interface to create families of related objects.
The Facade Pattern contributes to the principle of least knowledge (or Law of Demeter) by limiting the communication between objects. The client only needs to communicate with the facade, not with the subsystem classes. This reduces the dependencies between objects, making the system more robust and easier to maintain.
Yes, the Facade Pattern can be used in multi-threaded applications. However, care must be taken to ensure that the facade is thread-safe. This can be achieved by using synchronization mechanisms like locks or semaphores to prevent race conditions.
The Facade Pattern can improve performance by reducing the number of objects that the client needs to interact with. This can reduce the overhead of object creation and method invocation. However, if the facade becomes a bottleneck, it can negatively impact performance.
To implement the Facade Pattern in PHP, you need to create a facade class that provides a simplified interface to the complex subsystem. The facade class should encapsulate the subsystem and delegate calls to the subsystem classes. The client should interact with the subsystem through the facade, not directly with the subsystem classes.
The above is the detailed content of PHP Master | Manage Complexity with the Facade Pattern. For more information, please follow other related articles on the PHP Chinese website!