前面的單例模式及工廠模式都是屬於創建型設計模式,這裏要開始講結構型設計模式—門面模式。
這篇內容:
結構型設計模式概要
利用UML圖理解門面設計模式
門面模式與最少知識原則
理解結構型設計模式
結構型模式描述如何將對象和類組合成更大的結構
結構型模式是一種能夠簡化設計工作的模式,因爲它能夠找出更簡單的方法來認識或表示實體之間的關係。在面向對象世界中,結構型模式是一種能夠簡化設計工作的模式,因爲它能夠找出更簡單的方法來認識或表示實體之間的關係。在面向對象世界中,實體指的是對象或類。
類模式可以通過繼承來描述對象,從而提供更有用的程序接口,而對象模式則描述瞭如何將對象聯繫起來從而組成更大的對象,結構型模式是類和對象模式的綜合體。
##### 結構型設計模式例子:
- 適配器模式:將一個接口轉換爲客戶希望的另外一個接口。它試圖根據客戶端的需求來匹配不同類的接口。
- 橋接模式:該模式將對象的接口與其實現進行解耦,使得兩者可以獨立工作。
- 裝飾器模式:該模式允許在運行時或以動態方式爲對象添加職責。我們可以通過接口給對象添加某些屬性。
理解門面設計模式
門面(facade)通常是指建築物的表面,尤其是最有吸引力的那一面。它也可以一種讓人容易誤解某人的真實感受或情況的行爲或面貌。當人們從建築物外面經過時,可以欣賞其外部面貌,卻不瞭解建築物結構的複雜性。這就是門面模式的使用方式。門面在隱藏內部系統複雜性的同時,爲客戶端提供了一個接口,以便它們可以非常輕鬆地訪問系統。
假設你要到某個商店買東西,但是你是第一次來到這個商店,你對這個商店的佈局並不瞭解。所以一般你都會找店主,因爲店主對這個店裏面的情況瞭如執掌。只要你告訴他你要買什麼,店主就會把這些商品拿給你。這不就變得簡單了嗎。顧客不必瞭解店面裏面佈局情況,可以通過一個簡單的接口(店主)來完成購物。
門面設計模式實際上完成了下列事項:
-
它爲系統中的一組接口提供一個統一的接口,並定義一個高級接口來幫助客戶端通過更加簡單的方式使用子系統。
-
門面解決的是,如何使用單個接口對象來表示複雜的子系統。實際上,它並不是封裝子系統,而是對底層子系統進行組合。
-
它促進了實現與多個客戶端的解耦。
通過UML圖來深入探討門面模式:
就像你在UML圖所看這個模式有三個主要的參與者:
- 門面: 門面的主要責任是,將一組複雜導致系統封裝起來,從而爲外部世界提供一個舒適的外觀。
系統:這代表一組不同的子系統,使整個系統混雜在一起,難以觀察或使用。 - 客戶端:客戶端與門面進行交互,這樣就可以輕鬆地與子系統進行通信並完成工作了。不必擔心繫統複雜性。
1.門面:
- 它是一個接口,它知道某個請求可以交由哪個子系統進行處理。
- 它使用組合將客戶端的請求委派給相應的子系統使用。
例如:如果客戶端正在瞭解哪些工作已完成,則不需要到各個子系統中去,相反它只需要聯繫完成工作的接口(門面)就可以了
2.系統:
- 它實現子系統的功能,同時,系統由一個類表示。理想的情況下系統應該由一組負責不同任務的類來表示。
- 它處理門面對象的分配的工作,但並不知道門面,而且不引用它。
例如,當客戶端向門面請求某項服務時,門面會根據服務的類型來選擇該服務的相應子系統。
3.客戶端
- 客戶端是實例化門面的類。
- 爲了讓子系統完成相應的工作,客戶端需要向門面提出請求。
現實世界中實現門面模式(示例)
假設你要在家中舉行一場婚禮,並且由你來張羅這一切。這真是一個艱鉅的任務。你必須預訂一家酒店或場地,與餐飲人員交代酒菜、佈置場景,並安排背景音樂。、
你已經自己搞定了一切,如找相關人員談話、與他們進行協調、敲定價格等,那麼現在你就很輕鬆了。此外,你還可以去找會務經理,讓他/她爲你處理這些事情。會務經理負責跟各個服務提供商交涉,併爲你爭取最優惠的價格。
下面我們從門面模式的角度來看待這些事情。
客戶端:你需要在婚禮前及時完成所有的準備工作。每一項安排都應該是頂級的,這樣客人才會喜歡這些慶祝活動。
門面:會務經理負責與所有相關人員進行交涉,這些人員負責處理食物、花卉裝飾等。
子系統:它們代表提供餐飲、酒店管理和花卉裝飾等服務的系統。
讓我們利用Python開發一個應用程序,實現這個示例。我們首先從客戶端開始。記住,你是確保婚姻準備工作和事件順利的總負責人!
下面是EventManager類的Python代碼:
class EventManager(object):
"""
EventManager(活動經理)
Hotelier(旅館經理)
bookHotel(預定酒店)
Florist(花商)
setFlowerRequirements(花需求集)
Caterer(承辦酒席的人)
setCuisine(美食集)
Musician(樂師)
setMusicType(設置音樂類型)
"""
def __init__(self):
print('活動經理:讓我和大家談談\n')
def arrange(self):
self.hotelier = Hotelier()
self.hotelier.bookHotel()
self.florist = Florist()
self.florist.setFlowerRequirements()
self.caterer = Caterer()
self.caterer.setCuisine()
self.musician = Musician()
self.musician.setMusicType()
這裏已經搞定了門面和客戶端,讓我們開始深入瞭解子系統。
所以開發了這個類:
Hotelier類用於預訂酒店。它有一個方法,用於檢查當天是否有免費的酒店(__isAvailable)
Florist類負責花卉裝飾。這個類提供了setFlowerRequirements()方法,用於指定要使用哪些種類的花卉來裝飾婚禮。
Caterer類用於跟備辦宴席者打交道,並負責安排餐飲。Caterer提供了一個公開的setCuisine()方法,用來指定婚宴的菜餚類型。
Musician類用來安排婚禮的音樂,它使用setMusicType(方法來了解會務的音樂要求。
接下來,先來考察Hotelier對象,其次是Florist對象及其方法。
class Hotelier(object):
def __init__(self):
print('爲婚禮安排酒店?--')
def __isAvailable(self):
print("在指定的日子裏,酒店是免費的嗎?")
return True
def bookHotel(self):
if self.__isAvailable():
print("註冊預訂\n\n")
class Florist(object):
def __init__(self):
print("爲活動做的花裝飾?--")
def setFlowerRequirements(self):
print("康乃馨、玫瑰和百合用來裝飾\n\n")
class Caterer(object):
def __init__(self):
print("活動的食物安排--")
def setCuisine(self):
print("中餐和西菜\n\n")
class Musician(object):
def __init__(self):
print("婚禮的音樂安排--")
def setMusicType(self):
print("將播放爵士樂和古典音樂\n\n")
是,我很聰明,所以將這些事情都委託給了會務經理,不是嗎? 讓我們來看看You類。在本示例中,創建了一個EventManager類的對象,這樣經理就會通過與相關人員進行交涉來籌備婚禮,而你則可以找個地方喝大茶了。
class You(object):
def __init__(self):
print("你:哇!婚姻的安排???!!!")
def askEventManager(self):
print("讓我們聯繫一下活動經理\n\n")
em = EventManager()
em.arrange()
def __del__(self):
print("感謝活動經理,所有的準備工作都完成了!唷!")
you = You()
you.askEventManager()
將門面模式和現實世界場景關聯起來。
EventManager類是簡化接口的門面。
EvementManager通過組合創建子系統的對象,如Hotelier,Caterer等等。
最少知識原則
-
門面爲我們提供了一個統一的系統。它使得子系統更加易於使用。它還將客戶端與子系統解耦。門面設計模式背後的設計原理就是最少知識原則。
-
最少知識原則指導我們減少對象之間的交互,就像你親近的只有某幾個朋友那樣。
-
在設計系統時,對於創建的每個對象,都應該考察與之交互的類的數量, 以及交互的方式。
-
遵循這個原則,就能夠避免創建許多彼此緊密耦合的類的情況。
-
如果類之間存在大量依賴關係,那麼系統就會變得難以維護。如果對系統中的任何一部分進行修改,都可能導致系統的其他部分被無意改變,這意味着系統會退化,這是應該堅決避免的。
迪米特法則(設計準則)
- 每個單元對系統中其他單元知道的越少越好。
- 單位應該只與其朋友交流。
- 單元不應該知道它操作的對象的內部細則。
說明: 最少知識原則和迪米特法則是一致的,都是指向松耦合理論。就像它的名稱那樣,最少知識原則適用與門面模式的用例,並且原則這個詞是指導方針的意思,而不是嚴格遵守的意思,並且只有在有需求的時候才用。
問答
問.子系統可以有多個門面嗎?
答:是的,可以爲一組子系統組件實現多個門面。
問.最少知識原則的缺點是什麼?
答:門面提供了一個簡化的接口供客戶端與子系統交互。本着提供簡化接口的精神,應用可能會建立多個不必要的接口,這增加了系統的複雜性並且降低了運行時的性能。
問.客戶端可以獨立訪問子系統嗎?
答:是的,事實上,由於門面模式提供了簡化的接口,這使得客戶端不必擔心子系統的複雜性。
問.門面是否可以添加自己的功能?
答:門面可以將其“想法”添加到子系統中,例如確保子系統的改進順序由門面來決定。