二十二、外觀設計模式
1. 外觀設計模式介紹
顯示生活中有一個種電視萬能遙控器,只要和電視配對好了以後,就可以正常使用,不同型號的電視,只要一旦適配,所有的操作模式一模一樣。
這就是一種外觀適配模式。表面上都是同一個遙控器,實際上不同型號的電視,不同的操作,發出的型號可能各不相同。但是對於使用者來說,沒有任何差別。
定義
要求一個子系統的外部和其內部的通訊必須通過一個統一的物件進行。門面模式提供一個高層次的介面,使得子系統更易使用。
2. 外觀設計模式使用場景
為一個複雜的子系統提供簡單、固定的介面。比如我們常用的載入圖片的框架,隨著專案的推進,框架沒有人維護,或者出現了效率更高的框架出現,此時如果專案進行更換框架,可能需要修改很多處。如果,專案特別大,更是災難。但是如果我們之前採用了外觀設計模式,設計了統一的封裝介面,我們只需要接口裡面詳細的邏輯即可,而不必修改很多出。從外觀就好像沒有修改一樣。
當構建一個層次結構的子系統時,使用外觀設計模式定義子系統中每層的入口點。如果子系統之間是相互依賴的,那麼子系統之間可以通過外觀設計模式定義的介面進行通訊,簡化子系統之間的依賴關係。
3. 外觀設計模式UML類圖
4. 外觀設計模式簡單例項
現在以一個情形:一個子系統擁有三個模組,每個模組都有三個方法,其中一個為客戶端呼叫方法,其它兩個為各個子模組間互相呼叫方法。此時客戶端需要組合三個模組中的方法才能完成功能。
- (1)、A、B、C三個模組方法:
A 模組方法介面:
public interface AModuleApi {
//此方法用於外部呼叫
public void a1();
//以下兩個方法主要用於子系統內部間系統呼叫
public void a2();
public void a3();
}
A模組具體實現:
public class AModuleImpl implements AModuleApi {
@Override
public void a1() {
System.out.println("呼叫了A模組");
}
@Override
public void a2() {
//主要用於子模組間相互呼叫
}
@Override
public void a3() {
// 主要用於子模組間相互呼叫
}
}
以上是A模組中的方法,B、C兩個模組和A一樣。
- (2)、不採用外觀設計模式,客戶端如下:
public class Client {
public static void main(String[] args) {
AModuleApi aModule = new AModuleImpl();
aModule.a1();
BModuleApi bModule = new BModuleImpl();
bModule.b1();
CModuleImpl cModule = new CModuleImpl();
cModule.c1();
}
}
上面的程式碼我們會經常寫,自習詳細,會存在如下問題:
程式碼耦合度太高,客戶端與子系統中各模組都有關聯。一旦子系統有什麼更改,會涉及到客戶端的修改。
客戶端想要知道每個模組中各個方法的含義才能進行呼叫。
現在採用了外觀設計模式,新增一個外觀類,由外觀重組需要呼叫的方法
- (3)、新增一個外觀類介面:
public interface FacadeApi {
public void a1();
public void b1();
public void c1();
public void test();
}
- (4)、外觀類的具體實現:
public class FacadeImpl implements FacadeApi {
@Override
public void a1() {
new AModuleImpl().a1();
}
@Override
public void b1() {
new BModuleImpl().b1();
}
@Override
public void c1() {
new CModuleImpl().c1();
}
@Override
public void test() {
a1();
b1();
c1();
}
}
在test方法中,呼叫了三個模組中的方法。外觀類是在服務端的,不是這客戶端。客戶端不需要知道具體的內部實現是什麼樣的。
- (5)、客戶端:
public class Client {
public static void main(String[] args) {
/**
* 直接呼叫外觀類裡面的方法就可以了,內部細節不用知道,
* 計算改變了,也只需要呼叫這兩行程式碼即可。
*/
FacadeApi facade = new FacadeImpl();
facade.test();
}
}
客戶端只需要呼叫外觀模式中的程式碼即可,不需要關注具體實現細節。
5. 外觀設計模式在Android原始碼
我們經常在Activity中呼叫其他的方法,比如,Activity的跳轉,傳送廣播,啟動服務等。這些方法都是封裝在Context類中,Context是一個抽象類,具體實現是ContextImpl。
ContextImpl內部封裝了很多不同子系統的操作,上面說的這些操作就是在這裡面,然後它的具體實現並不在ContextImpl裡面,而是在各個不同的子系統進行處理。
這張圖就是ContextImpl和各個子類系統之間的呼叫關係:
6. 外觀設計模式在Android開發中
在開發中,我們經常會用到圖片載入,網路載入框架。有時候,隨著時間的推移,我們所使用框架的作者有可能不再維護,或者出現了效率更高的新的框架。
這時如果我們想要修改為新的框架,可能比較困難,可能太多的地方用到了。
但是如果我們採用了外觀設計模式,用了一個外觀類來包裝,呼叫的時候直接呼叫外觀方法,而不是直接呼叫。以後在需要修改的時候,只需要修改包裝類的方法即可。
例項:
public class ImageLoaer {
public Image loadImage(String url, int width, int height) {
//呼叫具體的圖片框架方法載入
}
}
7. 總結
- 優點:
- 對客戶端程式隱藏子系統細節,減少了客戶端對子系統的耦合。
- 外觀類對子系統的封裝,使得系統更易於使用。