Definition
Make a complex system simpler by providing a unified or general interface, which is a higher layer to these subsystems.Where to use & benefits
- Want to reduce complexities of a system.
- Decouple subsystems , reduce its dependency, and improve portability.
- Make an entry point to your subsystems.
- Minimize the communication and dependency between subsystems.
- Security and performance consideration.
- Shield clients from subsystem components.
- Simplify generosity to specification.
- Related patterns include
- Abstract Factory, which is often used to create an interface for a subsystem in an independent way, and can be used as an alternative way to a facade.
- Singleton, which is often used with a facade.
- Mediator, which is similar to facade, but a facade doesn't define new functionality to the subsystem.
Intent
01- Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
- Wrap a complicated subsystem with a simpler interface.
Problem
02A segment of the client community needs a simplified interface to the overall functionality of a complex subsystem.
This is how facade pattern is used. It hides the complexities of the system and provides an interface to the client from where the client can access the system. In Java, the interface JDBC can be called a facade. We as users or clients create connection using the “java.sql.Connection” interface, the implementation of which we are not concerned about. The implementation is left to the vendor of driver.
Let’s try and understand the facade pattern better using a simple example. Let’s consider a store. This store has a store keeper. In the storage, there are a lot of things stored e.g. packing material, raw material and finished goods.
You, as client want access to different goods. You do not know where the different materials are stored. You just have access to store keeper who knows his store well. Whatever you want, you tell the store keeper and he takes it out of store and hands it over to you on showing him the credentials. Here, the store keeper acts as the facade, as he hides the complexities of the system Store.
Let us see how the Store example works.
Store.java
package structural.facade; public interface Store { | ||
public Goods getGoods(); | ||
}// End of interface |
Similarly, the stores are of three types and can implement the Store interface. Let’s have a look at the code for one of the stores.
FinishedGoodsStore.java
package structural.facade; public class FinishedGoodsStore implements Store { | ||
public Goods getGoods() { FinishedGoods finishedGoods = new FinishedGoods(); return finishedGoods; } | ||
}// End of class |
StoreKeeper.java
package structural.facade; public class StoreKeeper { | ||
/** * The raw materials are asked for and * are returned * * @return raw materials */ public RawMaterialGoods getRawMaterialGoods() { RawMaterialStore store = new RawMaterialStore(); RawMaterialGoods rawMaterialGoods = (RawMaterialGoods)store.getGoods(); return rawMaterialGoods; } /** * The packaging materials are asked for and * are returned * * @return packaging materials */ public PackingMaterialGoods getPackingMaterialGoods() { PackingMaterialStore store = new PackingMaterialStore(); PackingMaterialGoods packingMaterialGoods = (PackingMaterialGoods)store.getGoods(); return packingMaterialGoods; } /** * The finished goods are asked for and * are returned * * @return finished goods */ public FinishedGoods getFinishedGoods() { FinishedGoodsStore store = new FinishedGoodsStore(); FinishedGoods finishedGoods = (FinishedGoods)store.getGoods(); return finishedGoods; } | ||
}// End of class |
How will the client program access this façade? Here is a simple code.
Client.java
package structural.facade; public class Client { | ||
/** * to get raw materials */ public static void main(String[] args) { StoreKeeper keeper = new StoreKeeper(); RawMaterialGoods rawMaterialGoods = keeper.getRawMaterialGoods(); } | ||
}// End of class |
There is another way of implementing this. We can have just one method in our StoreKeeper class getGoods(String goodsType).
Another version of StoreKeeper method is here.
StoreKeeper.java
package structural.facade; public class StoreKeeper { | ||
/** * The common method * * @return Goods */ public Goods getGoods(String goodsType) { if (goodsType.equals("Packaging")) { PackingMaterialStore store = new PackingMaterialStore(); PackingMaterialGoods packingMaterialGoods = (PackingMaterialGoods)store.getGoods(); return packingMaterialGoods; } else if (goodsType.equals("Finished")) { FinishedGoodsStore store = new FinishedGoodsStore(); FinishedGoods finishedGoods = (FinishedGoods)store.getGoods(); return finishedGoods; } else { RawMaterialStore store = new RawMaterialStore(); RawMaterialGoods rawMaterialGoods = (RawMaterialGoods)store.getGoods(); return rawMaterialGoods; } | ||
}// End of class |
new StoreKeeper().getGoods(“RawMaterials”);
In this case, the type-casting ill be needed on client side to narrow down Goods to RawMaterialsGoods.
All in all, the Façade pattern hides the complexities of system from the client and provides a simpler interface. Looking from other side, the facade also provides the implementation to be changed without affecting the client code.
Example 2:
Example
JDBC design is a good example of Façade pattern. A database design is complicated. JDBC is used to connect the database and manipulate data without exposing details to the clients.Security of a system may be designed with Façade pattern. Clients' authorization to access information may be classified. General users may be allowed to access general information; special guests may be allowed to access more information; administrators and executives may be allowed to access the most important information. These subsystems may be generalized by one interface. The identified users may be directed to the related subsystems.
interface General { public void accessGeneral(); } interface Special extends General { public void accessSpecial(); } interface Private extends General { public void accessPrivate(); } class GeneralInfo implements General { public void accessGeneral() { //... } //... } class SpecialInfo implements Special{ public void accessSpecial() { //... } public void accessGeneral() {} //... } class PrivateInfo implements Private, Special { public void accessPrivate() { // ... } public void accessSpecial() { //... } public void accessGeneral() { // ... } //... } class Connection { //... if (user is unauthorized) throw new Exception(); if (user is general) return new GeneralInfo(); if (user is special) return new SpecialInfo(); if (user is executive) return new PrivateInfo(); //... }The above code example illustrates that the whole system is not exposed to the clients. It depends on the user classification.
Mr. SudHakar Chavali proposes a better design, similar to the above, but avoids repeated code. Look at code below.
interface General { public void accessGeneral(); } interface Special extends General { public void accessSpecial(); } interface Private extends General { public void accessPrivate(); } class GeneralInfo implements General { public void accessGeneral() { //... } //... } class SpecialInfo extends GeneralInfo implements Special{ public void accessSpecial() { //... } } class PrivateInfo extends SpecialInfo implements Private { public void accessPrivate() { // ... } //... }To avoid repeated code, SpecialInfo become subclass of GeneralInfo and PrivateInfo becomes subclass of SpecialInfo. When a person is exposed to special information, that person is allowed to access general information also. When a person is exposed to private information, that person is allowed to access general information and special information also.
Example 3:
Facade in Java
Why read if you can watch?
Watch design patterns video tutorialFacade design pattern
01- Identify the desired unified interface for a set of subsystems
- Design a “wrapper” class that can encapsulate the use of the subsystems
- The client uses (is coupled to) the Facade
- The facade/wrapper “maps” to the APIs of the subsystems
// 1. Subsystem
class PointCarte {
private double x, y;
public PointCarte( double xx, double yy ) {
x = xx;
y = yy;
}
public void move( int dx, int dy ) {
x += dx;
y += dy;
}
public String toString() {
return "(" + x + "," + y + ")";
}
public double getX() {
return x;
}
public double getY() {
return y;
}
}
// 1. Subsystem
class PointPolar {
private double radius, angle;
public PointPolar( double r, double a ) {
radius = r;
angle = a;
}
public void rotate( int ang ) {
angle += ang % 360;
}
public String toString() {
return "[" + radius + "@" + angle + "]";
}
}
// 1. Desired interface: move(), rotate()
class Point {
private PointCarte pc; // 2. Design a "wrapper" class
public Point( double xx, double yy ) {
pc = new PointCarte( xx,yy );
}
public String toString() {
return pc.toString();
}
// 4. Wrapper maps
public void move( int dx, int dy ) {
pc.move( dx,dy );
}
public void rotate( int angle, Point o ) {
double x = pc.getX() - o.pc.getX();
double y = pc.getY() - o.pc.getY();
PointPolar pp = new PointPolar( Math.sqrt(x*x+y*y),
Math.atan2(y,x)*180/Math.PI );
// 4. Wrapper maps
pp.rotate( angle );
System.out.println( " PointPolar is " + pp );
String str = pp.toString(); int i = str.indexOf( '@' );
double r = Double.parseDouble( str.substring(1,i) );
double a = Double.parseDouble( str.substring(i+1,str.length()-1) );
pc = new PointCarte(r*Math.cos(a*Math.PI/180) + o.pc.getX(),
r*Math.sin(a*Math.PI/180) + o.pc.getY() );
}
}
class Line {
private Point o, e;
public Line( Point ori, Point end ) {
o = ori;
e = end;
}
public void move( int dx, int dy ) {
o.move( dx, dy );
e.move( dx, dy );
}
public void rotate( int angle ) {
e.rotate( angle, o );
}
public String toString() {
return "origin is " + o + ", end is " + e;
}
}
class FacadeDemo {
public static void main( String[] args ) {
// 3. Client uses the Facade
Line line1 = new Line( new Point(2,4), new Point(5,7) );
line1.move(-2,-4);
System.out.println( "after move: " + line1 );
line1.rotate(45);
System.out.println( "after rotate: " + line1 );
Line line2 = new Line( new Point(2,1), new Point(2.866,1.5) );
line2.rotate(30);
System.out.println( "30 degrees to 60 degrees: " + line2 );
}
}
after move: origin is (0.0,0.0), end is (3.0,3.0)
PointPolar is [4.242@90.0]
after rotate: origin is (0.0,0.0), end is (0.000,4.242)
PointPolar is [0.999@60.0]
30 degrees to 60 degrees: origin is (2.0,1.0), end is (2.499,1.866)
No comments:
Post a Comment