設計模式——08 外觀模式
08 Facade Pattern(外觀模式)
前言:讓介面變得簡單。
例子說明:
REQ1:還記得之前學習過的命令模式嗎,後面提出了開啟所有相關家電的命令,和關閉所有家電的命令,但是的目的就是為了可以一鍵進行一系列家電的操作,在這裡也類似。
Vander之前剛完成了上個設計,賺了很多錢,現在它入手了一整套小米裝備,有小米音響、小米空調、小米空氣淨化器、小米爆米花機、小米投影儀、小米投影幕布,它想在家裡開影院,製造一個良好的氛圍來好好享受這個週末。有以下這些家電:
分析:先來看看類圖,Vander發現買了一堆裝置,花了一大堆時間終於把這些裝置連線起來了,接下來要開啟這些裝置,想看一部電影需要完成:
1、開啟影院燈,調節成dim
2、開啟空氣淨化器
3、放下螢幕
4、開啟投影
5、將投影的輸入切換到dvd
6、設定投影成寬屏模式
7、開啟功放
8、功放的輸入為dvd
9、調節功放音量
10、開啟dvd
11、播放dvd
涉及到如此多的類,看完電影之後還要一個個關掉,這才頭疼,Vander心想:想過個心情愉悅的週末就這麼難嗎?將所有的步驟寫在一起,按照一定的順序,讓一個總控來幫我完成這些事情。然後Vander定義了一個家庭影院外觀(HomeTheaterFacade)。
分析:外觀模式允許我們讓客戶和子系統之間避免緊耦合。
外觀模式:提供一個統一的介面,用來訪問子系統中的一群介面。外觀定義了一個高層介面,讓子系統更容易使用。
這個模式可以通過實現一個提供更合理的介面的外觀類,可以將一個複雜的子系統變得容易使用。外觀模式不只是簡化了介面,也將客戶從元件的子系統中解耦。
外觀模式和介面卡模式比較:
1、外觀和介面卡都可以包裝許多類
2、外觀的意圖是簡化介面
3、介面卡的意圖是將介面轉成所需的介面
下面是模式的一般類圖:
介面卡模式很好地運用了OO的設計原則,使用物件組合,以修改的介面包裝被適配者。
影院物件:
public class HomeTheaterFacade {
private Amplifier amp;
private DvdPlayer dvd;
private AirCondition airCondition;
private Projector projector;
private Screen screen;
private TheaterLight theaterLight;
private Television television;
public HomeTheaterFacade(Amplifier amp, DvdPlayer dvd, AirCondition airCondition, Projector projector,
Screen screen, TheaterLight theaterLight, Television television) {
super();
this.amp = amp;
this.dvd = dvd;
this.airCondition = airCondition;
this.projector = projector;
this.screen = screen;
this.theaterLight = theaterLight;
this.television = television;
}
public void watchMoive(String moive) {
theaterLight.on();
theaterLight.dim();
screen.down();
airCondition.on();
projector.on();
projector.wideScreenMode();
amp.on();
amp.setDvdPlayer(dvd);
dvd.setAmplifier(amp);
dvd.on();
dvd.setVolume(10);
dvd.play(moive);
}
public void endMoive() {
screen.up();
airCondition.off();
projector.off();
amp.off();
dvd.off();
theaterLight.off();
}
public void watchTv() {
theaterLight.on();
airCondition.on();
amp.on();
amp.setTelevision(television);
television.on();
}
public void closeTv() {
television.off();
theaterLight.off();
airCondition.off();
amp.off();
}
}
音響:
public class Amplifier {
private DvdPlayer dvdPlayer;
private Television television;
private int volume;
public void on() {
System.out.println("Open Amplifier!");
}
public void off() {
System.out.println("Close Amplifier!");
}
public void setVolume(int volume) {
this.volume = volume;
}
public void setDvdPlayer(DvdPlayer dvdPlayer) {
this.dvdPlayer = dvdPlayer;
}
public void setTelevision(Television television) {
this.television = television;
}
public void play() {
if(this.dvdPlayer != null) {
System.out.println("Connect Dvd Player");
} else if(this.television != null ) {
System.out.println("Connect Television");
} else {
System.out.println("Connect Nothing");
}
System.out.println("Amplifier is" + this.volume);
}
}
實現的效果:
其餘的類都比較類似,這裡不一一列舉了,這裡只是為了說明HomeTheaterFacade提供了一個簡化的介面,讓使用者呼叫起來非常方便。
有了外觀模式最大的好處是減少了客戶跟子系統之間的緊密耦合,外觀模式幫我們很好地實現了一個原則——最小知識原則(Law of Demeter[墨忒耳法則])。
最小知識原則——只和你的密友談話。
意思是在設計一個系統的時候不管是任何物件都要注意它所互動的類有哪些,注意它和這些類是如何互動的。這個原則希望我們在設計中不要讓太多的類耦合在一起,免得修改系統中的一部分會影響到其他部分。如果許多類之間相互依賴,那麼這個系統就是一個易碎的系統。
遵循這個原則,我們物件設計中,該物件方法裡只應該呼叫屬於以下範圍的方法:
1、該物件本身
2、被當做方法的引數而傳遞進來的物件
3、此方法所建立或例項化的任何物件
4、物件的任何元件
前三條告訴我們,如果某物件是呼叫其他的方法的返回結果,不要呼叫該物件的方法。
第4條告訴我們裝配進來的可以呼叫。
EXP:
public float getTemp(){
//先拿到溫度計物件,再拿到溫度
Thermometer thermometer = station.getThermometer();
return thermometer.getTemperature();
}
public float getTemp(){
//在氣象站中加入方法,直接拿到溫度計物件
return station.getTemperature();
}
很顯然,第二種方法更具有優勢,getTemp方法所涉及到的類就少了一個。
舉例說明以上四種範圍的方法能夠被呼叫的情景:
EXP:
為了加深對這個原則的理解,下面再看兩段程式碼:
House1:
public class House1 {
WeatherStation station;
public float getTemp() {
return station.getThermometer().getTemperature();
}
}
House1明顯違反了最少知識原則,因為它呼叫的方法屬於第一次呼叫返回的物件。
House2:
public class House2 {
WeatherStation station;
public float getTemp() {
Thermometer thermometer = station.getThermometer();
return getTempHelper(thermometer);
}
private float getTempHelper(Thermometer thermometer) {
return thermometer.getTemperature();
}
}
House2雖然沒有違反最小知識原則,但是隻是為了形式上不違反規則而這麼寫,所以這樣並沒有意義。
缺點:最小知識原則雖然減少了物件之間的依賴,也減少了軟體的維護成本,但是採用這個原則也會導致更多的“包裝”類,以處理和其他元件的溝通,這可能會導致複雜度和開發時間的增加,並降低執行時的效能。
最後又到了喜聞樂見的總結部分,我們又來總結我們現在現有的設計模式武器。
面向物件基礎
抽象、封裝、多型、繼承
六大設計原則
設計原則一:封裝變化
設計原則二:針對介面程式設計,不針對實現程式設計。
設計原則三:多用組合,少用繼承。
設計原則四:為互動物件之間的鬆耦合設計而努力
設計原則五:對擴充套件開放,對修改關閉
設計原則六:依賴抽象,不要依賴於具體的類
設計原則七:只和你的密友談話
模式
外觀模式:提供了一個統一的介面,用來訪問子系統中的一群介面。外觀定義了一個高層介面,讓子系統更容易使用。
最後獻上此次設計所涉及到的原始碼,有需要的小夥伴可以下載來執行一下,首先先自己進行設計,然後再參考,這樣才能加深外觀模式的理解。