Day 11: Facade Pattern
Welcome back to Day 11 of our 30-Day Design Pattern Challenge! Today, we’ll delve into the Facade Pattern, a structural pattern that provides a simplified interface to a library, a framework, or any other complex set of classes.
What is it?
The Facade Pattern offers a simplified interface to a complex system of classes, components, or subsystems. It acts as a single point of entry, hiding the underlying complexities and providing a more user-friendly way to interact with the system.
Problem
Imagine that you must make your code work with a broad set of objects that belong to a sophisticated library or framework. Ordinarily, you’d need to initialize all of those objects, keep track of dependencies, execute methods in the correct order, and so on.
As a result, the business logic of your classes would become tightly coupled to the implementation details of 3rd-party classes, making it hard to comprehend and maintain.
Solution
A facade is a class that provides a simple interface to a complex subsystem which contains lots of moving parts. A facade might provide limited functionality in comparison to working with the subsystem directly. However, it includes only those features that clients really care about.
Having a facade is handy when you need to integrate your app with a sophisticated library that has dozens of features, but you just need a tiny bit of its functionality.
For instance, an app that uploads short funny videos with cats to social media could potentially use a professional video conversion library. However, all that it really needs is a class with the single method encode(filename, format)
. After creating such a class and connecting it with the video conversion library, you’ll have your first facade.
How to Implement
- Check whether it’s possible to provide a simpler interface than what an existing subsystem already provides. You’re on the right track if this interface makes the client code independent from many of the subsystem’s classes.
- Declare and implement this interface in a new facade class. The facade should redirect the calls from the client code to appropriate objects of the subsystem. The facade should be responsible for initializing the subsystem and managing its further life cycle unless the client code already does this.
- To get the full benefit from the pattern, make all the client code communicate with the subsystem only via the facade. Now the client code is protected from any changes in the subsystem code. For example, when a subsystem gets upgraded to a new version, you will only need to modify the code in the facade.
- If the facade becomes too big, consider extracting part of its behavior to a new, refined facade class.
Class Diagram
The class diagram involves these entities:
- Facade : Provides the simplified interface for the system.
- Subsystems : Represent the complex components of the system.
Example
- Problem Statement : Let’s consider a hotel. This hotel has a hotel keeper. There are a lot of restaurants inside the hotel e.g. Veg restaurants, Non-Veg restaurants, and Veg/Non Both restaurants. You, as a client want access to different menus of different restaurants. You do not know what are the different menus they have. You just have access to a hotel keeper who knows his hotel well. Whichever menu you want, you tell the hotel keeper and he takes it out of the respective restaurants and hands it over to you.
- Step wise Step Implementation of above problem
1. Interface of Hotel : The hotel interface only returns Menus. Similarly, the Restaurant are of three types and can implement the hotel interface. Let’s have a look at the code for one of the Restaurants.
package structural.facade;
public interface Hotel {
public Menus getMenus();
}
2. NonVegRestaurant.java
package structural.facade;
public class NonVegRestaurant implements Hotel {
public Menus getMenus()
{
NonVegMenu nv = new NonVegMenu();
return nv;
}
}
3. VegRestaurant.java
package structural.facade;
public class VegRestaurant implements Hotel {
public Menus getMenus()
{
VegMenu v = new VegMenu();
return v;
}
}
4. VegNonBothRestaurant.java
package structural.facade;
public class VegNonBothRestaurant implements Hotel {
public Menus getMenus()
{
Both b = new Both();
return b;
}
}
5. HotelKeeper.java
package structural.facade;
public interface HotelKeeper {
public VegMenu getVegMenu();
public NonVegMenu getNonVegMenu();
public Both getVegNonMenu();
}
4. HotelKeeperImplementation.java
package structural.facade;
public class HotelKeeperImplementation implements HotelKeeper {
public VegMenu getVegMenu()
{
VegRestaurant v = new VegRestaurant();
VegMenu vegMenu = (VegMenu)v.getMenus();
return vegMenu;
}
public NonVegMenu getNonVegMenu()
{
NonVegRestaurant v = new NonVegRestaurant();
NonVegMenu NonvegMenu = (NonVegMenu)v.getMenus();
return NonvegMenu;
}
public Both getVegNonMenu()
{
VegNonBothRestaurant v = new VegNonBothRestaurant();
Both bothMenu = (Both)v.getMenus();
return bothMenu;
}
}
- How will the client program access this facade?
package structural.facade;
public class Client
{
public static void main (String[] args)
{
HotelKeeper keeper = new HotelKeeperImplementation();
VegMenu v = keeper.getVegMenu();
NonVegMenu nv = keeper.getNonVegMenu();
Both = keeper.getVegNonMenu();
}
}
Other Examples
- Class
javax.faces.context.FacesContext
internally uses other types likeLifyCycle
andViewHandler
, so that the end user doesn't deal with them directly. javax.faces.context.ExternalContext
internally uses theHttpSession
,HttpServletRequest
and other classes. It acts as a facade for the consumers of the underlying classes.
Benefits
- Simplifies complex systems: Provides a clear and concise interface for user interaction.
- Reduces coupling: Users don’t need to know about individual components, promoting loose coupling.
- Improves maintainability: Changes to the underlying system can be localized within the facade.
Disadvantages
- Might introduce an extra layer of abstraction: Can potentially impact performance and add complexity.
- Limited flexibility: Might be inflexible if users require fine-grained control over individual components.
When to Use
- When dealing with complex systems with numerous interconnected components.
- When you want to provide a simplified user interface for interacting with a subsystem.
- When loose coupling between the client and the subsystem is desired.
When Not to Use
- For simple systems where a facade adds unnecessary overhead.
- When users require direct access to the underlying components for advanced functionalities.
Conclusion
The Facade Pattern offers a valuable approach to manage complex systems by providing a simplified interface. It promotes user-friendliness and loose coupling, making your system easier to maintain.
Stay tuned for Day 12, where we’ll explore Flyweight pattern! Feel free to leave comments or questions below. If you enjoyed this blog, consider giving it a clap 👏!