門面模式定義:要求一個子系統的外部與該子系統的內部通信必須通過一個統一的對象進行.
舉個栗子:我們在京東上網購商品,這是就需要一個Custormer類,並為該類定義一個Shopping()方法。假設京東只有三個部門:收銀部,倉儲部和物流部.
用戶購物需要這三個部門協調才能完成。
代碼清單-1 收銀部
public class PaymentImpl implements Payment {
public String pay(double price) {
String book = "書籍,《明朝那些事》";
System.out.println("您已付款:" + price + "元,購買的是:" + book);
return book;
}
}
代碼清單-2 倉儲部
/**
* 倉儲服務
*/
public class StorageImpl implements Storage{
/**
* 打包
* @param ware 商品
* @return
*/
public String pack(String ware) {
System.out.println("倉庫人員正在打包:" + ware);
return null;
}
}
代碼清單-3 物流部
/**
* 物流服務
*/
public class TransportImpl implements Transport{
/**
* 快遞
* @param ware 商品
* @return
*/
public String deliver(String ware) {
System.out.println("商品正在飛奔您懷中的路上:"+ware);
return null;
}
}
代碼清單-4 Custormer
public class Customer {
//購物
public void shopping(){
//依次創建三個部門
Payment payment = new PaymentImpl();
Storage storage = new StorageImpl();
Transport transport = new TransportImpl();
//支付
String ware = payment.pay(28.0);
//打包
storage.pack(ware);
//快遞運輸
transport.deliver(ware);
}
}
分析:正如上面的代碼所示,Customer需要依次調用三個部門的方法才能完成這個shopping方法,實際上,如果這個飯店有更多的部門,那麼程序就需要調用更多部門的方法來實現這個shopping方法——這就會增加shopping方法的實現難度了。
為了解決這個問題,我們可以為Payment、Storage、Transport三個部門提供一個門面(Facade),使用Facade來包裝這些類,對外提供一個簡單的訪問方法。
代碼清單-5 門面類
public class Facade {
private Payment payment;
private Storage storage;
private Transport transport;
public Facade(Payment payment, Storage storage, Transport transport) {
this.payment = payment;
this.storage = storage;
this.transport = transport;
}
public void fastShopping(){
//支付
String ware = payment.pay(28.0);
//打包
storage.pack(ware);
//快遞運輸
transport.deliver(ware);
}
}
那Customer的shopping方法就可以改為
public class Customer {
private Facade facade = null;
public Customer(Facade facade) {
this.facade = facade;
}
//購物
public void shopping(){
facade.fastShopping();
}
}
從上面的結構可以看出,如果不采用門面模式,客戶端需要自行決定需要調用哪些類、哪些方法,並需要按合理的順序來調用它們才能實現所需的功能。不采用門面模式時,程序有如圖所示的結構:

然而,使用了門面模式之後,客戶端代碼只需要和門面類進行交互即可,於是,程序結構圖變成了如下樣式:

其實,Spring的HibernateTemplate類就是使用的門面模式:當我們的程序使用Hibernate的find()方法時,程序只要一行代碼即可得到查詢返回的List。但實際上該find()方法後隱藏了如下代碼:
Session session = sf.openSession();
Query query = session.createQuery(hql);
for(int i=0; i<args.length; i++) {
query.setParameter(i, args[i]);
}
query.list();
因此我們可以認為HibernateTemplate是SessionFactory,Session、Query等類的門面。當客戶端程序需要進行持久化查詢時,程序無需調用這些類,而是直接調用HibernateTemplate門面類中的相印方法即可。
除此之外,JavaEE應用裡使用業務邏輯組件來封裝DAO組件也是典型的門面模式——每個業務邏輯組件(一般是Service層)都是眾多DAO組件的門面,系統的控制器類無需直接訪問DAO組件,而是由業務邏輯方法來組合多個DAO方法以完成所需功能。而Action只需與業務邏輯組件交互即可。