In this article I will write about the Facade Design Pattern and give you some examples for its usage.
About the Facade Design Pattern
A facade is for hiding features from external clients and to give them a unified access point to public functionality.
Let’s see what the Gang of Four (GoF) tells us about this pattern:
“Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use.”
So to have this pattern applied in your application your goal is to isolate your client from the code of your application.
You can use this pattern in a Service Oriented Architecture (SOA): for example a service enables access to other smaller services. You do not have to think in this case that these are web services and outside clients: you can have this pattern applied to your application too as you design it and restrict access between packages (this requires some build-time validation too however tools like SonarQube are capable of this).
Another way to use this pattern is to encapsulate complex functionality from the caller of your facade: you have a complex system in the background and when using this systems you need to fire up queries, ask other services and do various calculations to get the result. If you would access it normally you would need to know each service, the order to call them to get your result. With a facade in-between you only let one method known by your users and you can configure the logic in the facade.
Example
The best example is again the AppStore where we can order an app and we do not have to know what happens in the background: the app is developed and tested. And we are happy that we don’t have to call every phase of the development life-cycle ourself just the one facade.
Let’s see how this works with a simple example. In this app store we have a 3-phase development: first a Design is created by an AppDesigner based on some requirements. Then an AppDeveloper develops an App based on the Design. When the App is ready an AppTester verifies that the App is working as defined in the Design.
First of all, let’s create the Design and App classes:
/**
* Simple class to mock a design object for an app.
*
* @author GHajba
*
*/
public class Design {
private final String requirements;
public Design(final String requirements) {
this.requirements = requirements;
System.out.println(toString());
}
@Override
public String toString() {
return "App design for requirements: " + requirements;
}
}
/**
* Simple app mock which does nothing currently.
*
* @author GHajba
*
*/
public class App {
private final String title;
public App(final Design design, final String title) {
System.out.println("Creating an app based on the design: " + design);
this.title = title;
}
@Override
public String toString() {
return "Fantastic app with title: " + title;
}
}
Then we create the back-end workers:
/**
* Simple designer class.
*
* @author GHajba
*
*/
public class AppDesigner {
public static Design design(final String requirements) {
return new Design(requirements);
}
}
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Simple app developer mock.
*
* @author GHajba
*
*/
public class AppDeveloper {
private static final List<String> POSSIBLE_NAMES = Arrays.asList("Pointless Kangaroo",
"Moon Forgotten", "Purple Rusty Space", "Blue Vulture", "Skilled Ostrich", "Saturday's Intense Xylophone",
"Harsh Reborn Gravel", "Liquid Rhinestone", "Wooden Haystack", "Scissors Olive", "Moving Doorstop",
"Strong Restless Arm", "Dreaded Pottery");
public static App develop(final Design design) {
Collections.shuffle(POSSIBLE_NAMES);
return new App(design, POSSIBLE_NAMES.get(0));
}
}
/**
* A simple app tester.
*
* @author GHajba
*
*/
public class AppTester {
public static boolean test(final App app, final Design design) {
System.out.println("Testing app: " + app + ", based on the design " + design);
return Math.random() < 0.5;
}
}
Without a facade we have to know how every component works until we have our final App. An example of calling the workers is listed here:
/**
* Entry point for the application and here we can order our apps.
*
* @author GHajba
*
*/
public class AppStore {
public static void main(final String... args) {
Design d = AppDesigner.design(
"Create me a cool app which knows everything I want and makes this fast. And of course it has to be cheap.");
App app = AppDeveloper.develop(d);
while (!AppTester.test(app, d)) {
System.out.println("App " + app + " failed the tests :(");
}
}
}
And an example output:
App design for requirements: Create me a cool app which knows everything I want and makes this fast. And of course it has to be cheap.
Creating an app based on the design: App design for requirements: Create me a cool app which knows everything I want and makes this fast. And of course it has to be cheap.
Testing app: Fantastic app with title: Pointless Kangaroo, based on the design App design for requirements: Create me a cool app which knows everything I want and makes this fast. And of course it has to be cheap.
App Fantastic app with title: Pointless Kangaroo failed the tests :(
Testing app: Fantastic app with title: Pointless Kangaroo, based on the design App design for requirements: Create me a cool app which knows everything I want and makes this fast. And of course it has to be cheap.
App Fantastic app with title: Pointless Kangaroo failed the tests :(
Testing app: Fantastic app with title: Pointless Kangaroo, based on the design App design for requirements: Create me a cool app which knows everything I want and makes this fast. And of course it has to be cheap.
App Fantastic app with title: Pointless Kangaroo failed the tests :(
Testing app: Fantastic app with title: Pointless Kangaroo, based on the design App design for requirements: Create me a cool app which knows everything I want and makes this fast. And of course it has to be cheap.
To leverage our AppStore from the knowledge of who has to work on the App (perhaps we want to introduce some other step in the creation process like UX testers) we encapsulate the functionality into a facade:
/**
* This is the facade where the apps are created.
*
* @author GHajba
*
*/
public class AppCreationFacade {
public static App orderApp(final String requirements) {
Design d = AppDesigner.design(requirements);
App app = AppDeveloper.develop(d);
while (!AppTester.test(app, d)) {
System.out.println("App " + app + " failed the tests :(");
}
System.out.println("Successfully developed " + app);
return app;
}
}
As you can see, this facade does basically the same thing as we did previously in the AppStore. However with this approach we hide the implementation details from the clients of the facade and only the facade has to know how it gets an App from the initial requirements.
From the AppStore we only have to call the right method of the facade:
/**
* Entry point for the application and here we can order our apps.
*
* @author GHajba
*
*/
public class AppStore {
public static void main(final String... args) {
AppCreationFacade.orderApp(
"Create me a cool app which knows everything I want and makes this fast. And of course it has to be cheap.");
}
}
Here is an example output of the above example application:
App design for requirements: Create me a cool app which knows everything I want and makes this fast. And of course it has to be cheap.
Creating an app based on the design: App design for requirements: Create me a cool app which knows everything I want and makes this fast. And of course it has to be cheap.
Testing app: Fantastic app with title: Saturday’s Intense Xylophone, based on the design App design for requirements: Create me a cool app which knows everything I want and makes this fast. And of course it has to be cheap.
Successfully developed Fantastic app with title: Saturday’s Intense Xylophone
Conclusion
As you could see, using this design pattern is nothing tricky — and if you work with Java applications then you may already used this pattern without noticing it.