設計模式之適配器模式與外觀模式(二)
- 2019 年 12 月 26 日
- 筆記
好了,通過上次的學習,我們已經知道適配器模式是如何將一個類的介面轉換成另一個符合客戶期望的介面。同時也知道在Java中要做到這一點,必須將一個不兼容介面的對象包裝起來,變成兼容的對象。
我們現在要看一個改變介面的新模式,但是它改變介面的原因是為了簡化介面。這個模式被巧妙地命名為外觀模式(Facade-Pattern),之所以這麼稱呼,是因為它將一個或數個類的複雜的一切都隱藏在背後,只顯露出一個乾淨美好的外觀。
繁瑣的看電影步驟
還記得我們之前說過的命令模式中,一個遙控器能控制很多家電的過程吧。簡單的開關我們都會,複雜的模式,就比較麻煩,比如看電影的步驟:
- 打開爆米花機
- 開始爆米花
- 將燈光調暗
- 放下螢幕
- 打開投影機
- 將投影機的輸入切換到DVD
- 將投影機設置在寬屏模式
- 打開功放
- 將功放的輸入設置為DVD
- 將攻放設置為環繞立體聲
- 將攻放音量調到中
- 打開DVD播放器
- 開始播放DVD
看一個電影,真的是如此繁瑣。而且看完電影之後,還得過去把這些步驟都關閉。是用你的家庭影院竟然變得如此複雜!讓我們看看外觀模式如何解決這團混亂,好讓你輕鬆享受。
燈光、相機、外觀!
你需要的正是一個外觀:有了外觀模式,通過實現一個提供更合理的介面的外觀類,你可以將一個複雜的子系統變得容易使用。
- 我們為家庭影院系統創建一個外觀,命名為HomeTheaterFacade,它對外暴露出幾個簡單的方法,例如watchMovie()
- 這個外觀類將家庭影院諸多組件視為一個子系統,通過調用這個子系統,來實現watchMovie()方法
- 現在,你的客戶程式碼可以調用此家庭影院外觀所提供的方法,而不必再調用這個子系統的方法。
- 外觀只是提供你更直接的操作,並未將原來的子系統阻隔起來。如果你需要子系統類的更高層的功能呢,還是可以使用原來的子系統的
構造家庭影院外觀
好了,那接下來就到實戰階段啦。
第一步是使用組合讓外觀能夠訪問子系統中所有的組件
public class HomeTheaterFacade { Amplifier amp; Tuner tuner; DvdPlayer dvd; CdPlayer cd; Projector projector; TheaterLights lights; Screen screen; PopcornPopper popper; public HomeTheaterFacade(Amplifier amp, Tuner tuner, DvdPlayer dvd, CdPlayer cd, Projector projector, Screen screen, TheaterLights lights, PopcornPopper popper) { this.amp = amp; this.tuner = tuner; this.dvd = dvd; this.cd = cd; this.projector = projector; this.screen = screen; this.lights = lights; this.popper = popper; } // 將我們之前手動進行的每項任務依次處理。這裡每項任務都是委託子系統中相應的組件處理的 public void watchMovie(String movie) { System.out.println("Get ready to watch a movie..."); popper.on(); popper.pop(); lights.dim(10); screen.down(); projector.on(); projector.wideScreenMode(); amp.on(); amp.setDvd(dvd); amp.setSurroundSound(); amp.setVolume(5); dvd.on(); dvd.play(movie); } public void endMovie() { System.out.println("Shutting movie theater down..."); popper.off(); lights.on(); screen.up(); projector.off(); amp.off(); dvd.stop(); dvd.eject(); dvd.off(); } }
有了這個基礎,後面觀賞電影就變得簡單了。
public class HomeTheaterTestDrive { public static void main(String[] args) { Amplifier amp = new Amplifier("Top-O-Line Amplifier"); Tuner tuner = new Tuner("Top-O-Line AM/FM Tuner", amp); DvdPlayer dvd = new DvdPlayer("Top-O-Line DVD Player", amp); CdPlayer cd = new CdPlayer("Top-O-Line CD Player", amp); Projector projector = new Projector("Top-O-Line Projector", dvd); TheaterLights lights = new TheaterLights("Theater Ceiling Lights"); Screen screen = new Screen("Theater Screen"); PopcornPopper popper = new PopcornPopper("Popcorn Popper"); // 根據子系統所有的組件來實例化外觀 HomeTheaterFacade homeTheater = new HomeTheaterFacade(amp, tuner, dvd, cd, projector, screen, lights, popper); // 使用簡化的介面,並開啟電影,然後關閉電影 homeTheater.watchMovie("Raiders of the Lost Ark"); homeTheater.endMovie(); } }
就這樣,我們完成了外觀模式的處理。當你使用完,是不是覺得很簡單了呢。
定義外觀模式
想要用外觀模式,我們創建了一個介面簡化而統一的類,用來包裝子系統中一個或多個複雜的類。外觀模式相當直接,很容易理解,這方面和許多其他的模式不太一樣。但這並不會降低它的威力:外觀模式允許我們讓客戶和子系統之間避免緊耦合。而且外觀模式也幫我們遵循一個新的面向對象原則。
外觀模式提供了一個統一的介面,用來訪問子系統中的一群介面。外觀定義了一個高層介面,讓子系統更容易使用。
最少知識原則:只和你的密友談話。這個原則系統我們在設計中,不要讓太多的類耦合在一起,免得修改系統中的一部分,會影響到其他部分。如果許多類之間相互依賴,那麼這個系統就會變成一個易碎的系統,他需要花許多成本維護,也會因為太複雜而不容易被其他人了解。
我們來做一個對比大家就知道啦
// 不採用這個原則,我們需要調用兩次方法才能獲取到最終的資訊 public float getTemp() { Thermometer thermometer = station.getThermometer(); return thermometer.getTemperature(); } // 採用這個原則,我們加進一個方法,這樣就可以減少我們所依賴的類的數目 public float getTemp() { return station.getTemperature(); }
設計箱內的工具
因為這次學習的內容比較簡單,我就在這篇里進行總結了。
- OO基礎 抽象、封裝、繼承、多態
- OO原則 封裝變化 多用組合,少用繼承 針對介面編程,不針對實現編程 為交互對象之間的松耦合設計而努力 依賴抽象,不要依賴具體類 類應該對擴展開放,對修改關閉 只和朋友交談
- OO模式 『策略模式』、『觀察者模式』、『裝飾者模式』、『抽象工廠模式』、『工廠方法模式』、『單例模式』、『命令模式』 『適配器模式』將一個類的介面,轉換成客戶期望另一個介面。適配器讓原本不兼容的類合作無間。 『外觀模式』提供了一個統一的介面,用來訪問子系統中的一群介面。外觀定義了一個高層介面,讓子系統更容易使用。
這次學習的適配器和外觀,雖然篇幅不多,但是在平常寫程式碼的過程中還是經常使用的,尤其是適配器模式,你們覺得呢?所以,這一塊還得鞏固好,這樣對於後面編寫程式碼,理解程式碼的根源很有幫助的哦。下次,我們開啟模板方式模式之旅。
PS:小編在介紹適配器模式的時候,只舉例說明了對象適配器。其實還有一個類適配器,但是那個是需要用到多重繼承的,考慮到Java沒有實際場景,這裡就略過了。感興趣的朋友可以繼續深入研究下。