外觀模式(結(jié)構(gòu)型)
一、概述
外觀模式中,一個子系統(tǒng)的外部與其內(nèi)部的通信通過一個統(tǒng)一的外觀類進(jìn)行,外觀類將客戶類與子系統(tǒng)的內(nèi)部復(fù)雜性分隔開,使得客戶類只需要與外觀角色打交道,而不需要與子系統(tǒng)內(nèi)部的很多對象打交道。
外觀模式是一種使用頻率非常高的結(jié)構(gòu)型設(shè)計模式,它通過引入一個外觀角色來簡化客戶端與子系統(tǒng)之間的交互,為復(fù)雜的子系統(tǒng)調(diào)用提供一個統(tǒng)一的入口,降低子系統(tǒng)與客戶端的耦合度,且客戶端調(diào)用非常方便。
外觀模式:為子系統(tǒng)中的一組接口提供一個統(tǒng)一的入口。外觀模式定義了一個高層接口,這個接口使得這一子系統(tǒng)更加容易使用。
一種對象結(jié)構(gòu)型模式,是迪米特法則的一種具體實現(xiàn)。降低了原有系統(tǒng)的復(fù)雜度,同時也降低了客戶類與子系統(tǒng)的耦合度。
1). 示意圖

2). 相關(guān)角色
Facade(外觀角色):在客戶端可以調(diào)用它的方法,在外觀角色中可以知道相關(guān)的(一個或者多個)子系統(tǒng)的功能和責(zé)任;在正常情況下,它將所有從客戶端發(fā)來的請求委派到相應(yīng)的子系統(tǒng)去,傳遞給相應(yīng)的子系統(tǒng)對象處理。
SubSystem(子系統(tǒng)角色):在軟件系統(tǒng)中可以有一個或者多個子系統(tǒng)角色,每一個子系統(tǒng)可以不是一個單獨(dú)的類,而是一個類的集合,它實現(xiàn)子系統(tǒng)的功能;每一個子系統(tǒng)都可以被客戶端直接調(diào)用,或者被外觀角色調(diào)用,它處理由外觀類傳過來的請求;子系統(tǒng)并不知道外觀的存在,對于子系統(tǒng)而言,外觀角色僅僅是另外一個客戶端而已。
外觀模式雖然在一定程度降低了系統(tǒng)的耦合度,但是外觀模式在一定程度上并不符合開閉原則,增加新的子系統(tǒng)需要對原有系統(tǒng)進(jìn)行一定的修改,雖然修改量很小。
二、外觀模式案例
上述外觀模式不符合開閉原則,可以引入一個抽象外觀類,客戶端針對抽象外觀類編程,從而滿足開閉原則

圖中與代碼秒數(shù)有少許差異,但是無影響
/**
* 子系統(tǒng)
*/
class FileReader {
public String read(String fileNameSrc) {
System.out.println("讀取了文件");
return "文件內(nèi)容";
}
}
/**
* 子系統(tǒng)
*/
class FileWriter {
public void write(String encryptText, String fileName) {
System.out.println("將文件保存 -> " + fileName + ":" + encryptText);
}
}
/**
* 子系統(tǒng)
*/
class CipherMachine {
public String encrypt(String plainText) {
System.out.println("加密方式一加密后的文件");
return plainText;
}
}
/**
* 子系統(tǒng)
*/
class NewCipherMachine {
public String encrypt(String plainText) {
System.out.println("加密方式二加密后的文件");
return plainText;
}
}
/**
* 抽象外觀類
*/
interface IEncryptFacade {
abstract public void fileEncrypt(String fileNameSrc, String fileNameDes);
}
/**
* 具體外觀類1:
*/
class EncryptFacadeOne implements IEncryptFacade {
// 子系統(tǒng)
private FileReader reader;
private CipherMachine cipher;
private FileWriter writer;
public EncryptFacadeOne() {
reader = new FileReader();
cipher = new CipherMachine();
writer = new FileWriter();
}
// 統(tǒng)一處理的方法
@Override
public void fileEncrypt(String fileNameSrc, String fileNameDes) {
String plainStr = reader.read(fileNameSrc);
String encryptStr = cipher.encrypt(plainStr);
writer.write(encryptStr, fileNameDes);
}
}
/**
* 具體外觀類2:
*/
class EncryptFacadeTwo implements IEncryptFacade {
// 子系統(tǒng)
private FileReader reader;
private NewCipherMachine cipher;
private FileWriter writer;
public EncryptFacadeTwo() {
reader = new FileReader();
cipher = new NewCipherMachine();
writer = new FileWriter();
}
// 統(tǒng)一處理的方法
@Override
public void fileEncrypt(String fileNameSrc, String fileNameDes) {
String plainStr = reader.read(fileNameSrc);
String encryptStr = cipher.encrypt(plainStr);
writer.write(encryptStr, fileNameDes);
}
}
/**
* 測試客戶端
* @author Liucheng
* @since 2019-08-25
*/
public class ClientOne {
public static void main(String[] args) {
// 針對抽象外觀類編程
IEncryptFacade encryptFacade = new EncryptFacadeTwo();
encryptFacade.fileEncrypt("劉亦菲.txt", "仙女.txt");
}
}
三、外觀模式總結(jié)
外觀模式是一種使用頻率非常高的設(shè)計模式,它通過引入一個外觀角色來簡化客戶端與子系統(tǒng)之間的交互,為復(fù)雜的子系統(tǒng)調(diào)用提供一個統(tǒng)一的入口,使子系統(tǒng)與客戶端的耦合度降低,且客戶端調(diào)用非常方便。外觀模式并不給系統(tǒng)增加任何新功能,它僅僅是簡化調(diào)用接口。在幾乎所有的軟件中都能夠找到外觀模式的應(yīng)用,如絕大多數(shù)B/S系統(tǒng)都有一個首頁或者導(dǎo)航頁面,大部分C/S系統(tǒng)都提供了菜單或者工具欄,在這里,首頁和導(dǎo)航頁面就是B/S系統(tǒng)的外觀角色,而菜單和工具欄就是C/S系統(tǒng)的外觀角色,通過它們用戶可以快速訪問子系統(tǒng),降低了系統(tǒng)的復(fù)雜程度。所有涉及到與多個業(yè)務(wù)對象交互的場景都可以考慮使用外觀模式進(jìn)行重構(gòu)。
1). 優(yōu)點
- 它對客戶端屏蔽了子系統(tǒng)組件,減少了客戶端所需處理的對象數(shù)目,并使得子系統(tǒng)使用起來更加容易。通過引入外觀模式,客戶端代碼將變得很簡單,與之關(guān)聯(lián)的對象也很少。
- 它實現(xiàn)了子系統(tǒng)與客戶端之間的松耦合關(guān)系,這使得子系統(tǒng)的變化不會影響到調(diào)用它的客戶端,只需要調(diào)整外觀類即可。
- 一個子系統(tǒng)的修改對其他子系統(tǒng)沒有任何影響,而且子系統(tǒng)內(nèi)部變化也不會影響到外觀對象。
2). 缺點
- 不能很好地限制客戶端直接使用子系統(tǒng)類,如果對客戶端訪問子系統(tǒng)類做太多的限制則減少了可變性和靈活 性。
- 如果設(shè)計不當(dāng),增加新的子系統(tǒng)可能需要修改外觀類的源代碼,違背了開閉原則 使用抽象外觀類。
3). 適用場景
- 當(dāng)要為訪問一系列復(fù)雜的子系統(tǒng)提供一個簡單入口時可以使用外觀模式。
- 客戶端程序與多個子系統(tǒng)之間存在很大的依賴性。引入外觀類可以將子系統(tǒng)與客戶端解耦,從而提高子系統(tǒng)的獨(dú)立性和可移植性。
- 在層次化結(jié)構(gòu)中,可以使用外觀模式定義系統(tǒng)中每一層的入口,層與層之間不直接產(chǎn)生聯(lián)系,而通過外觀類建立聯(lián)系,降低層之間的耦合度。