Facade means the face of a building. While passing across a street, all we look at is the face of a building. The face abstracts all the complex implementation details of a building.
Similarly, a facade design pattern aims to provide a unified interface to a set of interfaces in the subsystem. This unified interface hides the subsystem complexity from the client. It falls under the category of structural patterns.
The java.util.Connection in Java is a facade as it allows us to create DB connections and hides the implementation details. Similarly, java.net.URL class is another facade that exposes the openStream() method hiding all involved details.
The facade pattern is usually a refactoring pattern. For a large complex subsystem, it’s a fairly good idea to use a facade pattern and provide the clients with a friendly interface to interact with.
Let’s start by defining an interface – BookGenre:
public interface BookGenre { List<Book> getBookList(); }
All classes representing different book categories will implement this interface:
public class Fiction implements BookGenre { ... } public class NonFiction implements BookGenre { ... } public class Technology implements BookGenre { ... }
We can let our client interact with all of the subsystem classes on its own to borrow a book.
But to simplify things out, let’s create a LibraryService as a facade which will expose these sort of functionalities:
public enum BookType { FICTION, NONFICTION, TECHNOLOGY } public class LibraryService { private BookGenre fiction; private BookGenre nonFiction; private BookGenre technology; public LibraryService() { this.fiction = new Fiction(); this.nonFiction = new NonFiction(); this.technology = new Technology(); } public void borrowBook(BookType type, String name) { List<Book> books; switch(type) { case FICTION: books = this.fiction.getBookList(); break; case NONFICTION: books = this.nonFiction.getBookList(); break; default: books = this.technology.getBookList(); } Book book = BookService.findBookByName(books, name); book.setAvailability(false); } ... }
For keeping the implementation simple, we have here assumed that there’s only a single book available against each book name.
Note that we haven’t added any additional functionality. The method borrowBook() uses the existing subsystems APIs to perform this operation.
We can represent the above example as:
With this facade in place, our client can directly interact with it and avoid dealing with the system internal details on its own.
Let’s quickly recap a few important points:
In this tutorial, we explored another structural design pattern known as the facade pattern. It’s a refactoring pattern that’s mostly used to provide a simpler face to a complex poorly designed subsystem.