一 ?定義
為子系統中的一組接口提供一個一致的界面。Facade模式定義了一個高層的接口,這個接口使得這一子系統更加easy使用。
二 ?案例
一個子系統中擁有3個模塊。每一個模塊中都有3個方法。當中一個為client調用方法,其它兩個則為各子模塊間互相調用方法。此時有例如以下需求,client為完畢功能。須要組合3個模塊中的方法才干實現功能。
三 ?未使用模式情況
/*** @Description A模塊* @author jerry * @date 2016年4月11日下午2:16:04*/
public interface AModuleApi {public void a1(); //此方法主要用于外部調用public void a2(); //下面雙方法主要用于子系統內部間調用public void a3();
}
/*** @Description A模塊實現* @author jerry * @date 2016年4月11日下午2:17:10*/
public class AModuleImpl implements AModuleApi {@Overridepublic void a1() {System.out.println("調用了A模塊");}@Overridepublic void a2() {//TODO 主要用于子模塊間互相調用}@Overridepublic void a3() {//TODO 主要用于子模塊間互相調用}
}
/*** @Description B模塊* @author jerry * @date 2016年4月11日下午2:16:12*/
public interface BModuleApi {public void b1(); //此方法主要用于外部調用public void b2(); //下面雙方法主要用于子系統內部間調用public void b3();
}
/*** @Description B模塊實現* @author jerry * @date 2016年4月11日下午2:17:10*/
public class BModuleImpl implements BModuleApi {@Overridepublic void b1() {System.out.println("調用了B模塊");}@Overridepublic void b2() {//TODO 主要用于子模塊間互相調用}@Overridepublic void b3() {//TODO 主要用于子模塊間互相調用}
}
同理。C模塊也是如此,篇幅原因。這里不貼代碼了,須要代碼能夠從我github下clone,文末會給出地址。client調用例如以下:
public class Client {public static void main(String[] args) {AModuleApi a = new AModuleImpl();a.a1();BModuleApi b = new BModuleImpl();b.b1();CModuleApi c = new CModuleImpl();c.c1();}
}
相信非常easy能夠寫出這種代碼。細致想想能夠發現,假設這樣寫。會存在例如以下問題:
- 代碼耦合度太高,client與子系統中各模塊都有關聯。一旦子系統有什么更改,會涉及到client的改動。
- 對client學習成本太高。client須要學習各個模塊中每一個public方法。知道其什么含義后才干進行調用。
四 ?使用模式的情況
我們能夠在系統這端(即外觀模式屬于系統這端,若屬于客戶這端。仍然須要客戶去了解每一個模塊每一個方法意義,這樣無不論什么意義。) 加入一個外觀類,由外觀類重組須要調用的方法,例如以下所看到的:
/*** @Description 外觀類,通常設計成單例* @author jerry * @date 2016年4月11日下午2:43:26*/
public class Facade {private Facade(){}public static void test(){AModuleApi a = new AModuleImpl();a.a1();BModuleApi b = new BModuleImpl();b.b1();CModuleApi c = new CModuleImpl();c.c1();}
}
public class Client {public static void main(String[] args) {
// AModuleApi a = new AModuleImpl();
// a.a1();
// BModuleApi b = new BModuleImpl();
// b.b1();
// CModuleApi c = new CModuleImpl();
// c.c1();Facade.test();}
}
這樣一來。client僅僅要與外觀類打交道就可以,從而更好地實現了client和子系統各模塊的耦合性。使用外觀的目的: 不是給子系統加入新的功能接口,而是讓外部降低對子系統內部多個模塊的直接交互。松散耦合,從而可以讓外部更簡單地使用子系統。
當然有時你會有這種需求,client可能僅僅須要調用兩個模塊就可以,那么現有的外觀模式就無法使用了,僅僅好繞開外觀類。直接找各模塊進行調用。此外,你是否發現。我的ABC模塊里面除了有供外部調用的方法外。還有各模塊間互相調用的方法,這些方法本不須要client了解。暴露了過多內部細節。會讓client產生疑惑,這就是“接口污染”? 。要解決問題,我們能夠將Facade類定義為接口,并對事實上現,使用工廠模式對其創建實例,例如以下所看到的:
當然有時你會有這種需求,client可能僅僅須要調用兩個模塊就可以,那么現有的外觀模式就無法使用了,僅僅好繞開外觀類。直接找各模塊進行調用。此外,你是否發現。我的ABC模塊里面除了有供外部調用的方法外。還有各模塊間互相調用的方法,這些方法本不須要client了解。暴露了過多內部細節。會讓client產生疑惑,這就是“接口污染”? 。要解決問題,我們能夠將Facade類定義為接口,并對事實上現,使用工廠模式對其創建實例,例如以下所看到的:
public interface FacadeApi {public void a1();public void b1();public void c1();/*** @Description 原有方法,將各模塊方法組合調用* @return void* @throws */public void test();
}
/*** @Description 外觀接口實現* @author jerry * @date 2016年4月11日下午3:19:25*/
public class FacadeImpl implements FacadeApi {@Overridepublic void a1() {new AModuleImpl().a1();}@Overridepublic void b1() {new BModuleImpl().b1();}@Overridepublic void c1() {new CModuleImpl().c1();}@Overridepublic void test() {a1();b1();c1();}
}
/*** @Description 外觀接口實現* @author jerry * @date 2016年4月11日下午3:19:25*/
public class FacadeImpl implements FacadeApi {@Overridepublic void a1() {new AModuleImpl().a1();}@Overridepublic void b1() {new BModuleImpl().b1();}@Overridepublic void c1() {new CModuleImpl().c1();}@Overridepublic void test() {a1();b1();c1();}
}
public class Client {public static void main(String[] args) {
// AModuleApi a = new AModuleImpl();
// a.a1();
// BModuleApi b = new BModuleImpl();
// b.b1();
// CModuleApi c = new CModuleImpl();
// c.c1();// Facade.test();FacadeApi api = Factory.createFacade();api.test();}
}
這樣以后,就對client降低了模塊內部方法的暴露。五 ?總結
外觀模式的本質:封裝交互。簡化調用
何時使用外觀模式:
- 假設你希望為一個復雜的子系統提供一個簡單接口
- 假設構建多層結構的系統。能夠考慮使用外觀模式,使用外觀對象作為每層的入口,這樣能夠簡化層間調用,能夠減少耦合度。
------------------------------------------------------------------------------------------------------------------------------------------
Github: ?https://github.com/jerry-sc/designPattern