設計模式之介面卡模式與外觀模式(二)
好了,通過上次的學習,我們已經知道介面卡模式是如何將一個類的介面轉換成另一個符合客戶期望的介面。同時也知道在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沒有實際場景,這裡就略過了。感興趣的朋友可以繼續深入研究下。
愛生活,愛學習,愛感悟,愛挨踢
相關推薦
C之有符號與無符號(二)
C語言 有符號數 無符號數 我們在 C 語言中經常會見到 unsigned 關鍵字,那麽這是什麽意思呢?在計算機內,數據類型分為有符號和無符號兩種類型。它的最高位用於標識數據的符號:如果最高位為 1,表明這個數為負數;如果是0的則表明這個數為正數。那麽我們就來做個試驗驗證下,代碼如
jQuery 之 選擇器與事件型別(二)
hover() hover()方法用於模擬游標懸停事件.當滑鼠移動到元素上時,會觸發指定的第一個函式(mouseenter);當滑鼠移出這個元素時,會觸發指定的第二個函式(mouseleave)。 例項 $("#p1").hover(function(){ alert("You entered p1!")
VIVADO FIR濾波器設計與仿真(二)
put tps ilo 用法 ilog ril [ ] 技術 仿真 VIVADO FIR濾波器設計與仿真(二) 在VIVADO FIR濾波器設計與仿真(一)中產生了兩路正弦信號,頻率分別為4MHz和5MHz,今天要進行FIR濾波器設計,在進行濾波器設計之前,需要對濾波器的參
從壹開始微服務 [ DDD ] 之六 ║聚合 與 聚合根 (下)
前言 哈嘍大家週二好,上次咱們說到了實體與值物件的簡單知識,相信大家也是稍微有些瞭解,其實實體咱們平時用的很多了,基本可以和資料庫表進行聯絡,只不過值物件可能不是很熟悉,值物件簡單來說就是在DDD領域驅動設計中,為了更好的展示領域模型之間的關係,制定的一個物件,它沒有狀態和標識,目的就是為了表示一個值。今天
django之ORM介紹與基本用法(一)
一、ORM介紹 1.什麼是ORM ORM 全拼Object-Relation Mapping. 中文意為 物件-關係對映. 在MVC/MVT設計模式中的Model模組中都包括ORM 2.ORM優勢 (1)只需要面
0x05演算法設計與分析複習(二):演算法設計策略-分治法2
參考書籍:演算法設計與分析——C++語言描述(第二版) 演算法設計策略-分治法 二分搜尋 問題描述 在有序表(已按關鍵字值非減排序)中搜索給定元素的問題。 分治法求解 設有一個長度為n的有序表(a0,a1,⋯,an−1),要求
從零開始學C++之虛擬函式與多型(一):虛擬函式表指標、虛解構函式、object slicing與虛擬函式、C++物件模型圖
#include <iostream>using namespace std;class CObject {public: virtual void Serialize() { cout << "CObject::Serialize ..." <&
shell命令之檔案壓縮與解壓(常用)
.tar 解包:tar xvf FileName.tar 打包:tar cvf FileName.tar DirName (注:tar是打包,不是壓縮!) .gz 解壓1:gunzip FileName.gz 解壓2:gzip -d Fil
JAVA:IO流 之 節點流與處理流(2)
1. 流的分類 按資料流的方向不同:輸入流,輸出流。 按處理資料單位不同:位元組流,字元流。 (1) 位元組流:資料流中最小的資料單元是位元組。 (2)字元流:資料流中最小的資料單元是字元, Java中的字元是Unicode編碼,一個字元佔用兩個位元組。
Qt自定義控制元件的建立與初步使用(二)之圖片上繪製文字、箭頭、曲線
本文目的:編輯自定義控制元件的介面ui,並在圖片上添文字、箭頭、曲線、開啟、儲存等功能。並說明了如何去使用這個編輯好的ui介面控制元件! 上次簡單的說明了如何去建立Qt自定義控制元件,當時還是對其瞭解不夠深刻,現在看來,QT自定義控制元件就是你事先把介面寫好(一般基於QWi
FPGA之同步復位與非同步復位(1)
正常情況下,clk的上升沿c更新為b,b更新為a。一旦進入復位,b,c都清零;但是我們不能確定復位訊號rst_n會在什麼時候結束。如果結束於b_reg0和c_reg0的{launch edge –stup,launch edge+hold}時間只外,那麼一切都會正常。但如果恰恰相反,會出現什麼情況呢? rst
靜態分析之資料流分析與 SSA 入門 (二)
什麼是靜態單賦值 SSA SSA 是 static single assignment 的縮寫,也就是靜態單賦值形式。顧名思義,就是每個變數只有唯一的賦值。 以下圖為例,左圖是原始程式碼,裡面有分支, y 變數在不同路徑中有不同賦值,最後列印 y 的值。右圖是等價的 SS
FPGA之同步復位與非同步復位(2)
為了避免純粹的同步復位和純粹非同步復位的問題,可以使用一種叫做同步化的非同步復位,我們稱其為第三類復位。這種復位完全結合了非同步復位和同步復位的優勢,我們知道非同步復位的優勢是不參與資料路徑,所以不影響資料路徑速度,而復位幾乎是瞬間起作用;而同步復位的優勢是百分百地同步時
無線通訊網路學習之E-UTRAN與EPC篇(20141209)
今天來介紹一下E-UTRAN和EPC中網元架構方面的知識: 首先來參考一下下面的一張拓撲圖: 從圖中可以看出,E-UTRAN是使用者的移動終端(UE)與基站eNodeB組成; 負責無線訊號控制與資料處理,無線資源管理(Radio Resource Manageme
Java基礎之File類與IO流(三)
一、記憶體流 使用記憶體流的需求: 把一個網路上的圖片儲存到陣列中,但是圖片的大小不能確定,怎樣解決? 記憶體流主要用來操作記憶體 ByteArrayInputStream和ByteArrayOutputStream 輸入和輸出可以把檔案作為
Java靜態分派與動態分派(二)
xiang oid main isp 準備 center 使用 name 編譯過程 方法調用並不等於方法執行,方法調用階段唯一的任務就是確定被調用方法的版本(即調用哪一個方法),暫時還不涉及方法內部的具體運行過程。 在程序運行時,進行方法調用是最普遍、最頻繁的操作,但是Cl
python學習之函數學習進階(二)
python學習之函數進階二一、內置函數 zip函數: zip()是Python的一個內建函數,它接受一系列可叠代的對象作為參數,將對象中對應的 元素按順序組合成一個tuple,每個tuple中包含的是原有序列中對應序號位置的元素,然後返回由 這些tuples組成的list。若傳入參數的長度不等,則返回li
linux設備驅動之平臺總線實踐環節(二)
linux設備驅動模型1、上一節中,我們將初步的驅動代碼寫完後編譯後,放入到rootfs中進行insmod時,在/sys/bus/platform/drvier/目錄中能夠看到why_led這個目錄,但是進入後只有一些基本的東西,卻沒有能使用這個led驅動的關鍵性東西,那是因為我們沒有提供platform_d
solr搜索之demo和集成IKAnalyzer(二)
solr solr搜索 ikanalyzer分詞器 ikanalyzer 1 新建demo-solr關閉運行的solr應用。進入solr目錄:D:\solr-4.10.2\example1、在example目錄下創建demo-solr文件夾;2、將./solr下的solr.xml拷貝
Spark源代碼分析之六:Task調度(二)
oge 3.4 總結 utili filter 相關 .com ram 順序 話說在《Spark源代碼分析之五:Task調度(一)》一文中,我們對Task調度分析到了DriverEndpoint的makeOffers()方法。這種方法針對接收到的Re