大家好,我們今天來一起學習一個新的設計模式,叫做媒介模式。
所謂的媒介其實是一種封裝的思想,把某些功能共同的邏輯抽象出來做成一個中間的媒介,從而減少代碼之間的耦合,提升拓展性,更加方便日后的需求變更。
簡單案例
我們用一個實際的例子來認知一下媒介這個設計模式。
假設我們要做一個聊天室,如果真要去做的話,這里面會非常復雜,涉及到很多網絡編程的知識,比如廣播、客戶端、服務端等等。為了方便演示,我們把這些都簡化了。這樣簡化到極致之后,我們的聊天室代碼就只有幾行:
class User:
def __init__(self, name):
self.name = name
def say(self, message):
call_something()
print('[{} says:] {}'.format(self.name, message))
這段邏輯沒什么好說的,大家應該都能看懂。假設我們就這么完成了產品經理的需求,會有一個什么問題呢?
功能上當然是OK的,但是系統設計上有兩個比較大的問題。第一個是邏輯重復的問題,我們在User也就是聊天室中用戶對象的類當中實現了怎么在聊天室當中聊天的功能。我們會發現用戶之間的私聊,用戶之間的視頻、語言等可能都會用到差不多的邏輯,比如建立網絡連接,比如發送消息,判斷消息是否發送成功等等。
但是現在這些邏輯是寫死在User這個類里了,如果其他類想要使用,根本沒法復用,只能把代碼拷貝一份。這樣拷貝來拷貝去就會使得代碼變得非常混亂,變得難以維護。
第二個問題是邏輯耦合的問題,User這個類是聊天室的用戶對象類,但是其中實現了很多聊天室的功能。表面上看是簡單了,但其實是聊天室和用戶這兩個不同概念的代碼耦合在一起了。很多垃圾項目都有這個問題,明明A本身就應該是一個單獨的實體,結果我卻需要去修改B當中的代碼。時間一長,連開發者自己都會忘記當初實現某某的邏輯放在哪里。
通過對這個案例的分析,其實也是對為什么要使用設計模式這個問題的回答。設計模式大多數情況下並不能直接提升項目的運行效率,它最大的功能是為了代碼的拓展性以及可維護性。如果不使用合理的設計模式,隨着功能的增多,項目代碼和逐漸變得越來越臃腫,直到人類難以維護的地步。
媒介模式
回歸正題,那么我們怎么樣來使用媒介設計模式來解決上面的這兩個問題呢?
其實很簡單,我們直接來看代碼吧:
class ChatRoom:
def display_message(self, user, message):
print('[{} says]: {}'.format(user, message))
class User:
def __init__(self, name):
self.name = name
self.chat_room = ChatRoom()
def say(self, message):
self.chat_room.display_message(self, message)
也就是說我們抽象出了一個ChatRoom這個類,將聊天室的功能從User類當中剝離了出去,並且將它作為了User類的一個成員變量。這樣做的好處是,當以后聊天室的功能需要復用或者是需要修改的時候,我們可以避免對User類的打擾。不然的話,開發人員需要在User類的一堆代碼當中准確找到聊天室的相關邏輯進行修改,相信我,這絕不是什么很好的體驗。
當然,到這里並沒有優化到極致,由於User這個類的實例很多,我們會發現每次我們創建一個User的實例都會產生一個ChatRoom的實例,這其實是非常多余並且沒有必要的。所以我們可以把ChatRoom設計成單例模式,不管User創建多少實例,獲得的ChatRoom都是同一個,這樣就節省了內存開銷。
我們用單例模式來改寫一下ChatRoom的代碼:
import threading
class ChatRoom:
_lock = threading.Lock()
def __init__(self):
pass
def __new__(cls, *algs, **kw):
if not hasattr(ChatRoom, '_instance'):
with ChatRoom._lock:
if not hasattr(ChatRoom, '_instance'):
ChatRoom._instance = object.__new__(cls)
return ChatRoom._instance
到這里,這個問題才算是被優化到了極限。看似很簡單的一個功能,其實當中涉及的細節和思考還是很多的,絕不是表面上看起來的那么簡單,這些內容書本上往往是學不到的,只能通過自己的實踐和思考來獲得。
今天的文章就到這里,衷心祝願大家每天都有所收獲。如果還喜歡今天的內容的話,請來一個三連支持吧~(點贊、關注、轉發)