Java設(shè)計模式之java外觀模式詳解
模式動機

引入外觀角色之后,用戶只需要直接與外觀角色交互,用戶與子系統(tǒng)之間的復雜關(guān)系由外觀角色來實現(xiàn),從而降低了系統(tǒng)的耦合度。

模式定義
外觀模式是一種使用頻率非常高的結(jié)構(gòu)型設(shè)計模式,它通過引入一個外觀角色來簡化客戶端與子系統(tǒng)之間的交互,為復雜的子系統(tǒng)調(diào)用提供一個統(tǒng)一的入口,降低子系統(tǒng)與客戶端的耦合度,且客戶端調(diào)用非常方便。
外觀模式又稱為門面模式,它是一種對象結(jié)構(gòu)型模式。外觀模式是迪米特法則的一種具體實現(xiàn),通過引入一個新的外觀角色可以降低原有系統(tǒng)的復雜度,同時降低客戶類與子系統(tǒng)的耦合度。
模式結(jié)構(gòu)

角色
- Facade(外觀角色):在客戶端可以調(diào)用它的方法,在外觀角色中可以知道相關(guān)的(一個或者多個)子系統(tǒng)的功能和責任;在正常情況下,它將所有從客戶端發(fā)來的請求委派到相應的子系統(tǒng)去,傳遞給相應的子系統(tǒng)對象處理。
- SubSystem(子系統(tǒng)角色):在軟件系統(tǒng)中可以有一個或者多個子系統(tǒng)角色,每一個子系統(tǒng)可以不是一個單獨的類,而是一個類的集合,它實現(xiàn)子系統(tǒng)的功能;每一個子系統(tǒng)都可以被客戶端直接調(diào)用,或者被外觀角色調(diào)用,它處理由外觀類傳過來的請求;子系統(tǒng)并不知道外觀的存在,對于子系統(tǒng)而言,外觀角色僅僅是另外一個客戶端而已。
外觀模式的目的不是給予子系統(tǒng)添加新的功能接口,而是為了讓外部減少與子系統(tǒng)內(nèi)多個模塊的交互,松散耦合,從而讓外部能夠更簡單地使用子系統(tǒng)。
外觀模式的本質(zhì)是:封裝交互,簡化調(diào)用。
模式分析
根據(jù)“單一職責原則”,在軟件中將一個系統(tǒng)劃分為若干個子系統(tǒng)有利于降低整個系統(tǒng)的復雜性,一個常見的設(shè)計目標是使子系統(tǒng)間的通信和相互依賴關(guān)系達到最小,而達到該目標的途徑之一就是引入一個外觀對象,它為子系統(tǒng)的訪問提供了一個簡單而單一的入口。
外觀模式也是“迪米特法則”的體現(xiàn),通過引入一個新的外觀類可以降低原有系統(tǒng)的復雜度,同時降低客戶類與子系統(tǒng)類的耦合度。
外觀模式要求一個子系統(tǒng)的外部與其內(nèi)部的通信通過一個統(tǒng)一的外觀對象進行,外觀類將客戶端與子系統(tǒng)的內(nèi)部復雜性分隔開,使得客戶端只需要與外觀對象打交道,而不需要與子系統(tǒng)內(nèi)部的很多對象打交道。
外觀模式的目的在于降低系統(tǒng)的復雜程度。
外觀模式從很大程度上提高了客戶端使用的便捷性,使得客戶端無須關(guān)心子系統(tǒng)的工作細節(jié),通過外觀角色即可調(diào)用相關(guān)功能。
典型的外觀角色代碼
public class Facade
{
private SubSystemA obj1 = new SubSystemA();
private SubSystemB obj2 = new SubSystemB();
private SubSystemC obj3 = new SubSystemC();
public void method()
{
obj1.method();
obj2.method();
obj3.method();
}
}
外觀模式實例與解析
實例一:電源總開關(guān)
現(xiàn)在考察一個電源總開關(guān)的例子,以便進一步說明外觀模式。為了使用方便,一個電源總開關(guān)可以控制四盞燈、一個風扇、一臺空調(diào)和一臺電視機的啟動和關(guān)閉。通過該電源總開關(guān)可以同時控制上述所有電器設(shè)備,使用外觀模式設(shè)計該系統(tǒng)

//子系統(tǒng)角色
public class Fan
{
private Fan(){}
private static Fan instance;
//靜態(tài)代碼塊中創(chuàng)建單例對象
static {
instance=new Fan();
}
public static Fan getInstance()
{
return instance;
}
public void on()
{
System.out.println("風扇開");
}
public void off()
{
System.out.println("風扇關(guān)");
}
}
//子系統(tǒng)角色
public class Light
{
//靜態(tài)常量
private static Light instance=new Light();;
//構(gòu)造器私有化
private Light(){};
//共有靜態(tài)方法,返回一個實例對象
public static Light getInstance()
{
return instance;
}
public void on()
{
System.out.println("燈開");
}
public void off()
{
System.out.println("燈關(guān)");
}
}
//外觀角色
public class GeneralSwitchFaced
{
private Light light;
private Fan fan;
public GeneralSwitchFaced()
{
light=Light.getInstance();
fan=Fan.getInstance();
}
public void on()
{
light.on();
fan.on();
}
public void off()
{
light.off();
fan.off();
}
}
//測試
public class Test
{
@org.junit.Test
public void test()
{
GeneralSwitchFaced faced=new GeneralSwitchFaced();
faced.on();
faced.off();
}
}

實例二:文件加密
某系統(tǒng)需要提供一個文件加密模塊,加密流程包括三個操作,分別是讀取源文件、加密、保存加密之后的文件。讀取文件和保存文件使用流來實現(xiàn),這三個操作相對獨立,其業(yè)務代碼封裝在三個不同的類中?,F(xiàn)在需要提供一個統(tǒng)一的加密外觀類,用戶可以直接使用該加密外觀類完成文件的讀取、加密和保存三個操作,而不需要與每一個類進行交互,使用外觀模式設(shè)計該加密模塊。

通過外觀角色的一個方法,封裝了三個獨立的操作過程,即將文件的加密過程封裝在了外觀角色的文件加密方法中,客戶通過調(diào)用該方法即可完成對文件的加密,無需挨個調(diào)用三個獨立的操作
模式優(yōu)缺點
優(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)一般不需要編譯所有其他的子系統(tǒng)。一個子系統(tǒng)的修改對其他子系統(tǒng)沒有任何影響,而且子系統(tǒng)內(nèi)部變化也不會影響到外觀對象
- 只是提供了一個訪問子系統(tǒng)的統(tǒng)一入口,并不影響用戶直接使用子系統(tǒng)類。
缺點
- 不能很好地限制客戶使用子系統(tǒng)類,如果對客戶訪問子系統(tǒng)類做太多的限制則減少了可變性和靈活性。
- 在不引入抽象外觀類的情況下,增加新的子系統(tǒng)可能需要修改外觀類或客戶端的源代碼,違背了“開閉原則”。
模式適用環(huán)境
- 當要為一個復雜子系統(tǒng)提供一個簡單接口時可以使用外觀模式。該接口可以滿足大多數(shù)用戶的需求,而且用戶也可以越過外觀類直接訪問子系統(tǒng)。
- 客戶程序與多個子系統(tǒng)之間存在很大的依賴性。引入外觀類將子系統(tǒng)與客戶以及其他子系統(tǒng)解耦,可以提高子系統(tǒng)的獨立性和可移植性。
- 在層次化結(jié)構(gòu)中,可以使用外觀模式定義系統(tǒng)中每一層的入口,層與層之間不直接產(chǎn)生聯(lián)系,而通過外觀類建立聯(lián)系,降低層之間的耦合度。
源碼分析外觀模式的典型應用
(1) 外觀模式應用于JDBC數(shù)據(jù)庫操作
public class JDBCFacade {
private Connection conn=null;
private Statement statement=null;
public void open(String driver,String jdbcUrl,String userName,String userPwd) {
......
}
public int executeUpdate(String sql) {
......
}
public ResultSet executeQuery(String sql) {
......
}
public void close() {
......
}
}
(2) Session外觀模式是外觀模式在Java EE框架中的應用

模式擴展
一個系統(tǒng)有多個外觀類
在外觀模式中,通常只需要一個外觀類,并且此外觀類只有一個實例,換言之它是一個單例類。在很多情況下為了節(jié)約系統(tǒng)資源,一般將外觀類設(shè)計為單例類。當然這并不意味著在整個系統(tǒng)里只能有一個外觀類,在一個系統(tǒng)中可以設(shè)計多個外觀類,每個外觀類都負責和一些特定的子系統(tǒng)交互,向用戶提供相應的業(yè)務功能。
不要試圖通過外觀類為子系統(tǒng)增加新行為
不要通過繼承一個外觀類在子系統(tǒng)中加入新的行為,這種做法是錯誤的。外觀模式的用意是為子系統(tǒng)提供一個集中化和簡化的溝通渠道,而不是向子系統(tǒng)加入新的行為,新的行為的增加應該通過修改原有子系統(tǒng)類或增加新的子系統(tǒng)類來實現(xiàn),不能通過外觀類來實現(xiàn)。
外觀模式與迪米特法則
外觀模式創(chuàng)造出一個外觀對象,將客戶端所涉及的屬于一個子系統(tǒng)的協(xié)作伙伴的數(shù)量減到最少,使得客戶端與子系統(tǒng)內(nèi)部的對象的相互作用被外觀對象所取代。外觀類充當了客戶類與子系統(tǒng)類之間的“第三者”,降低了客戶類與子系統(tǒng)類之間的耦合度,外觀模式就是實現(xiàn)代碼重構(gòu)以便達到“迪米特法則”要求的一個強有力的武器。
抽象外觀類的引入
外觀模式最大的缺點在于違背了“開閉原則”,當增加新的子系統(tǒng)或者移除子系統(tǒng)時需要修改外觀類,可以通過引入抽象外觀類在一定程度上解決該問題,客戶端針對抽象外觀類進行編程。對于新的業(yè)務需求,不修改原有外觀類,而對應增加一個新的具體外觀類,由新的具體外觀類來關(guān)聯(lián)新的子系統(tǒng)對象,同時通過修改配置文件來達到不修改源代碼并更換外觀類的目的。

總結(jié)

參考文章
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
SpringBoot中l(wèi)ogback日志保存到mongoDB的方法
這篇文章主要介紹了SpringBoot中l(wèi)ogback日志保存到mongoDB的方法,2017-11-11
Java實現(xiàn)連接kubernates集群的兩種方式詳解
這篇文章主要為大家詳細介紹了Java實現(xiàn)連接kubernates集群的兩種方式,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下2024-01-01
Spring中的接口重試機制spring-retry之listeners參數(shù)解析
這篇文章主要介紹了Spring中的接口重試機制spring-retry之listeners參數(shù)解析,注解@Retryable有一個參數(shù)listeners沒有說明,那么本篇文章我們詳細介紹一個這個參數(shù)的用,需要的朋友可以參考下2024-01-01
如何自定義Jackson序列化?@JsonSerialize
這篇文章主要介紹了如何自定義Jackson序列化?@JsonSerialize,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
SpringBoot整合Lucene實現(xiàn)全文檢索的詳細步驟
全文搜索(Full-Text?Search)是指對大規(guī)模存儲在計算機系統(tǒng)中的文本數(shù)據(jù)進行檢索和匹配的技術(shù),它允許用戶輸入關(guān)鍵字,然后從海量的文本數(shù)據(jù)中快速找到相關(guān)的信息,本文介紹了SpringBoot整合Lucene實現(xiàn)全文檢索的詳細步驟,需要的朋友可以參考下2024-03-03
java中synchronized關(guān)鍵字的3種寫法實例
synchronized是Java中的關(guān)鍵字,是一種同步鎖,下面這篇文章主要給大家介紹了關(guān)于java中synchronized關(guān)鍵字的3種寫法,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下2021-11-11

