上一篇《python設計模式-介面卡模式》介紹瞭如何將一個類的介面轉換成另一個符合期望的介面。這一篇將要介紹需要一個為了簡化介面而改變介面的新模式-外觀模式(Facade-Pattern)。
問題
問題
:如果你組裝了一套家庭影院,內含播放器、投影機、自動螢幕、立體聲音響、爆米花機等。如何設計一個遙控器,可以簡單的操作這個系統中的各個元件呢?
首先來看一下最笨方式觀賞電影的步驟:
- 開啟爆米花機
- 開始爆米花
- 將燈光調暗
- 放下螢幕
- 開啟投影儀
- 將投影機的輸入切換到播放器
- 將投影及設定在寬屏模式
- 開啟功放
- 將功放的輸入設定為播放器
- 將攻防設定為環繞立體聲
- 將攻防音量調到適中
- 開啟播放器
- 播放電影
寫成類和方法的呼叫大概是以下的樣子:
# 開啟爆米花機,開始爆米花
poper.on()
poper.pop()
# 燈光調暗
lights.dim(10)
# 放下螢幕
screen.down()
# 開啟投影儀,設定為寬屏模式
projector.on()
projector.setInput(dvd)
projector.wideScreenMode()
# 開啟功放 設定為DVD 調整成環繞立體聲模式,音量調到5
amp.on()
amp.setDvd(dvd)
amp.setSurroundSound()
amp.setVolume(5)
# 開啟dvd 播放器
dvd.on()
dvd.play(movie)
複製程式碼
可以看到程式碼中涉及到6個不同的類,而且電影看完後還需要回退,一切都要再反著重來一遍。怎樣簡化一下操作呢? 現在,外觀模式就可以大展身手了。
使用外觀模式,可以通過實現一個提供更合理的介面的外觀類,將子系統變得更容易使用。當然,原來的介面還在。
解決方法
先來看一下外觀模式如何運作
- 這裡為家庭影院系統建立了一個新的外觀類
HomeTheaterFacade
,這個類暴露出來幾個簡單的方法,比如watchMovie
,endMovie
。 - 這個外觀類將家庭影院的多個元件看作一個子系統,通過呼叫這個子系統來實現
watchMovie
方法。 - 外觀只提供了一個更直接的操作方式,並沒有將原來的子系統隔離,子系統的功能還可以使用
注意:
- 可以有多個外觀
- 外觀提供簡化的介面,但不隔離子系統
- 外觀將實現從子系統中解耦,比如:現在有個子系統的元件需要升級換代,只需要把外觀程式碼做相應的修改就可以實現
- 外觀和介面卡都可以包裝多個類,但是
外觀的意圖時簡化介面的呼叫
,而介面卡的意圖是將介面轉換成不同的介面
。
示例
class HomeTheaterFacade(object):
#先宣告需要用的子元件
amp = Amplifier()
tuner = Tuner()
dvd = DvdPlayer()
cd = CdPlayer()
projector = Projector()
lights = TheaterLights()
screen = Screen()
popper = PopcornPopper()
def watchMovie(self, movie):
# watchMovie 將之前需要手動處理的任務批量處理
print("Get ready to watch a movie...")
# 開啟爆米花機,開始爆米花
self.poper.on()
self.poper.pop()
# 燈光調暗
self.lights.dim(10)
# 放下螢幕
self.screen.down()
# 開啟投影儀,設定為寬屏模式
self.projector.on()
self.projector.setInput(dvd)
self.projector.wideScreenMode()
# 開啟功放 設定為DVD 調整成環繞立體聲模式,音量調到5
self.amp.on()
self.amp.setDvd(dvd)
self.amp.setSurroundSound()
self.amp.setVolume(5)
# 開啟dvd 播放器
self.dvd.on()
self.dvd.play(movie)
def endMovie(self):
# endMovie 負責關閉一切,由子系統中的元件完成
print("Shutting movie theater down...")
self.popper.off()
self.lights.on()
self.screen.up()
self.projector.off()
self.amp.off()
self.dvd.stop()
self.dvd.eject()
self.dvd.off()
複製程式碼
程式碼使用
def main():
home_theater = HomeTheaterFacade() # 例項化外觀
home_theater.watchMovice() # 使用簡化方法開啟 關閉電影ß
home_theater.endMovice()
複製程式碼
定義
定義:
外觀模式提供了一個統一的介面,用來訪問子系統中的一群介面。外觀定義了一個高層介面,讓子系統更容易使用。
從類圖也可以瞭解到,外觀模式的主要意圖是提供一個更簡單易用的介面。
最少知識原則(least Knowledge)
最少知識原則
的意思是減少物件之間的互動,只和幾個特定的物件互動。
這個原則是希望在設計中,不要耦合太多的類,以免修改系統時,會影響到其它部分。
比如:如果想從DVD播放器獲取音響的音量,可以在Dvd播放器中加入一個方法,用來像音響請求當前音量,而不是先返回音響物件,再從音響物件返回音量。
# 不好的實踐
def get_volume():
tuner = dvd.tuner()
return tuner.get_volume
# 好的實踐
def get_volume():
# 這裡要給dvd 物件加一個get_volume方法
return dvd.get_volume
複製程式碼
缺點:
雖然這個原則減少了物件之間的依賴,但是也會導致更多的包裝被製造出來(比如上邊例子中,就需要給dvd 加一個 get_volume
方法),這也可能會導致系統更復雜。
再回顧一下外觀模式的例子,會發現外觀模式符合最少知識原則
,客戶端只有HomeTheaterFacade
這一個互動物件。它的存在讓系統呼叫變的更簡單,並且如果需要子系統有模組需要升級,只需要修改HomeTheaterFacade
這個類就可以完成升級。
本文例子來自《Head First 設計模式》。
最後,感謝女朋友支援和包容,比❤️
也可以在公號輸入以下關鍵字獲取歷史文章:公號&小程式
| 設計模式
| 併發&協程