python 設(shè)計模式之責(zé)任鏈模式
1. 責(zé)任鏈模式
通俗點(diǎn)講,責(zé)任鏈?zhǔn)且粋€鏈表結(jié)構(gòu),這條鏈上有多個節(jié)點(diǎn),它們有相同的接口,各自有各自的責(zé)任和實現(xiàn)。當(dāng)有數(shù)據(jù)輸入時,第一個節(jié)點(diǎn)看自己能否處理問題,如果可以就進(jìn)行處理,如果不能就數(shù)據(jù)交給下一個節(jié)點(diǎn)進(jìn)行處理,以此類推直到最后一個責(zé)任節(jié)點(diǎn)。
上面這段描述里,我們可以總結(jié)出以下幾個關(guān)鍵信息
鏈表
相同的接口
節(jié)點(diǎn)有各自的任務(wù)
從第一個節(jié)點(diǎn)開始處理輸入,如果不能處理,交給下一個節(jié)點(diǎn)
為了實現(xiàn)相同的接口,在責(zé)任鏈模式中需要一個抽象處理者角色來定義一個抽象接口,責(zé)任鏈上的節(jié)點(diǎn)是具體處理者角色,處理者必須實現(xiàn)由抽象處理者定義的抽象接口并各自實現(xiàn)具體功能。
2. 責(zé)任鏈模式示例
在網(wǎng)站上設(shè)置密碼時,對密碼通常有如下要求:
密碼長度大于6
包含小寫字母和大寫字母
包含特殊字符
我就以檢查密碼是否合法為例子講解如何實現(xiàn)責(zé)任鏈模式,當(dāng)然,實踐中這樣的檢查是不需要使用責(zé)任鏈來實現(xiàn)的,只是這個例子更通俗易懂一些。
2.1 抽象處理者角色
from abc import ABC, abstractmethod
class AbcCheckHandler(ABC):
@abstractmethod
def check_password(self, password):
pass
@abstractmethod
def set_next(self, handler):
pass
AbcCheckHandler 類是抽象處理者角色,它存在的意義是定義具體處理者角色必須實現(xiàn)的接口,這樣處理者角色在使用時才能規(guī)范行為。
2.2 具體處理者角色
具體處理者角色是抽象處理者角色的子類
class CheckHanlderBase(AbcCheckHandler):
_next_handler = None
def set_next(self, handler):
self._next_handler = handler
@abstractmethod
def _check(self, password):
pass
def check_password(self, password):
status, msg = self._check(password)
if status:
if self._next_handler:
return self._next_handler.check_password(password)
else:
return True, ''
else:
return status, msg
class LengthCheckHandler(CheckHanlderBase):
"""
專門檢查長度
"""
def _check(self, password):
if len(password) > 6:
return True, ''
return False, '長度錯誤'
class CaseCheckHandler(CheckHanlderBase):
"""
專門檢查大小寫
"""
def _check(self, password):
has_lower = False
has_upper = False
for letter in password:
if 'a' < letter < 'z':
has_lower = True
if 'A' < letter < 'Z':
has_upper = True
if has_lower and has_upper:
return True, ''
else:
return False, '大小寫不符合要求'
class SpecialCheckHandler(CheckHanlderBase):
def _check(self, password):
for letter in ('!', '@', '#', '$'):
if letter in password:
return True, ''
return False, '未包含特殊字符'
def check_password(password):
len_checker = LengthCheckHandler()
case_checker = CaseCheckHandler()
special_checker = SpecialCheckHandler()
len_checker.set_next(case_checker)
case_checker.set_next(special_checker)
status, msg = len_checker.check_password(password)
if status:
print(f"{password} 檢查通過")
else:
print(f"{password} 檢查不通過: {msg}")
LengthCheckHandler, CaseCheckHandler, SpecialCheckHandler這3個類是具體處理者角色,他們是CheckHanlderBase的子類,而CheckHanlderBase 是AbcCheckHandler的子類,我特地增加了CheckHanlderBase,為的是讓代碼更加簡潔,你可以去掉它,讓三個檢查類直接繼承AbcCheckHandler,但那樣很多代碼都會重復(fù)。
2.3 調(diào)用責(zé)任鏈
def get_password_checker():
len_checker = LengthCheckHandler()
case_checker = CaseCheckHandler()
special_checker = SpecialCheckHandler()
len_checker.set_next(case_checker)
case_checker.set_next(special_checker)
return len_checker
def check_password(password):
password_checker = get_password_checker()
status, msg = password_checker.check_password(password)
if status:
print(f"{password} 檢查通過")
else:
print(f"{password} 檢查不通過: {msg}")
if __name__ == "__main__":
check_password("1324sfED!")
check_password("323!")
check_password("323df3!")
check_password("323DKS3!")
check_password("skdjOWRJ")
對于責(zé)任鏈的調(diào)用者,你不必關(guān)心鏈上有多少個節(jié)點(diǎn),節(jié)點(diǎn)的順序是什么,這些都是在創(chuàng)建責(zé)任鏈時決定的,由創(chuàng)建者負(fù)責(zé),你只需要將數(shù)據(jù)輸入給責(zé)任鏈即可。
3. 責(zé)任鏈模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
增加或者刪除責(zé)任很方便
降低耦合度,對于請求的發(fā)送者,無需關(guān)心接收者都有哪些,順序如何
缺點(diǎn):
可能會在程序調(diào)試方面制造一些麻煩,但可以通過合理的日志輸出來規(guī)避

