java設計模式-外觀模式
外觀模式是一種使用頻率非常高的結構型設計模式,它通過引入一個外觀角色來簡化客戶端與子系統之間的互動,為複雜的子系統呼叫提供一個統一的入口,降低子系統與客戶端的耦合度,且客戶端呼叫非常方便。外觀模式通過引入一個新的外觀類(Facade)來實現該功能,外觀類充當了軟體系統中的“服務員”,它為多個業務類的呼叫提供了一個統一的入口,簡化了類與類之間的互動。外觀模式中,一個子系統的外部與其內部的通訊通過一個統一的外觀類進行,外觀類將客戶類與子系統的內部複雜性分隔開,使得客戶類只需要與外觀角色打交道,而不需要與子系統內部的很多物件打交道。
外觀模式定義如下: 外觀模式:為子系統中的一組介面提供一個統一的入口。外觀模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。
包含角色:
(1) Facade(外觀角色):在客戶端可以呼叫它的方法,在外觀角色中可以知道相關的(一個或者多個)子系統的功能和責任;在正常情況下,它將所有從客戶端發來的請求委派到相應的子系統去,傳遞給相應的子系統物件處理。 (2) SubSystem(子系統角色):在軟體系統中可以有一個或者多個子系統角色,每一個子系統可以不是一個單獨的類,而是一個類的集合,它實現子系統的功能;每一個子系統都可以被客戶端直接呼叫,或者被外觀角色呼叫,它處理由外觀類傳過來的請求;子系統並不知道外觀的存在,對於子系統而言,外觀角色僅僅是另外一個客戶端而已。
下面我們通過一個應用例項來理解和學習外觀模式。
例項說明:
** * 檔案加密 */ public class FileEncrypt { /** * 檔案加密 */ public String encryptFile(String file) { String enFile = "abc" + file; //省略檔案具體加密過程 System.out.println("檔案加密完成 :" +enFile); return enFile; } } /** * 檔案讀取操作類 */ public class FileReader { /** * 檔案讀取方法 */ public String readFile(String filePath) { String file = filePath; // 省略流讀取方法、 System.out.println("讀取檔案為 :" + file); return file; } } /** * 檔案寫入 */ public class FileWriter { /** * 檔案儲存 */ public void write(String file) { // 省略儲存方法 System.out.println("檔案儲存成功!"); } } /** * 外觀裝飾類 */ public class EncryptFacade { private FileReader fileReader; private FileEncrypt fileEncrypt; private FileWriter fileWriter; public EncryptFacade() { this.fileReader = new FileReader(); this.fileEncrypt = new FileEncrypt(); this.fileWriter = new FileWriter(); } //呼叫其他物件的業務方法 public void fileEncrypt(String filePath){ String plainStr = fileReader.readFile(filePath); String encryptStr = fileEncrypt.encryptFile(plainStr); fileWriter.write(encryptStr); } } public class Client { public static void main(String[] args) { String filePath = "1.text"; EncryptFacade encryptFacade = new EncryptFacade(); encryptFacade.fileEncrypt(filePath); } } 輸出結果: 讀取檔案為 :1.text 檔案加密完成 :abc1.text 檔案儲存成功!
在標準的外觀模式結構圖中,如果需要增加、刪除或更換與外觀類互動的子系統類,必須修改外觀類或客戶端的原始碼,這將違背開閉原則,因此可以通過引入抽象外觀類來對系統進行改進,在一定程度上可以解決該問題。下面通過一個具體例項來學習如何使用抽象外觀類:
如果在應用例項“檔案加密模組”中需要更換一個加密類,如果不增加新的外觀類只能通過修改原有外觀類EncryptFacade的原始碼來實現加密類的更換,這樣違背了開閉原則。所以我們需要引入抽象外觀類來解決這一問題。
/**
* 抽象外觀類
*/
public abstract class AbstractEncryptFacade {
public abstract void fileEncrypt(String filePath);
}
/**
* 整合抽象外觀類
*/
public class NewEncryptFacade extends AbstractEncryptFacade {
// 引入新的加密類,其它不變
/**
* 重寫抽象外觀方法
*/
@Override
public void fileEncrypt(String filePath) {
}
}
public class Client {
public static void main(String[] args) {
String filePath = "1.text";
//EncryptFacade encryptFacade = new EncryptFacade();
//encryptFacade.fileEncrypt(filePath);
AbstractEncryptFacade abstractEncryptFacade = new NewEncryptFacade();
abstractEncryptFacade.fileEncrypt(filePath);
}
}
優點:
(1) 它對客戶端遮蔽了子系統元件,減少了客戶端所需處理的物件數目,並使得子系統使用起來更加容易。通過引入外觀模式,客戶端程式碼將變得很簡單,與之關聯的物件也很少。 (2) 它實現了子系統與客戶端之間的鬆耦合關係,這使得子系統的變化不會影響到呼叫它的客戶端,只需要調整外觀類即可。 (3) 一個子系統的修改對其他子系統沒有任何影響,而且子系統內部變化也不會影響到外觀物件。
缺點:
(1) 不能很好地限制客戶端直接使用子系統類,如果對客戶端訪問子系統類做太多的限制則減少了可變性和靈活性。 (2) 如果設計不當,增加新的子系統可能需要修改外觀類的原始碼,違背了開閉原則。
適用場景:
(1) 當要為訪問一系列複雜的子系統提供一個簡單入口時可以使用外觀模式。 (2) 客戶端程式與多個子系統之間存在很大的依賴性。引入外觀類可以將子系統與客戶端解耦,從而提高子系統的獨立性和可移植性。
(3) 在層次化結構中,可以使用外觀模式定義系統中每一層的入口,層與層之間不直接產生聯絡,而通過外觀類建立聯絡,降低層之間的耦合度。