[Python設計模式] 第24章 加薪審批——職責鏈模式

github地址:https://github.com/cheesezh/python_design_patternspython

題目

用程序模擬如下情景git

  • 員工向經理髮起加薪申請,經理無權決定,須要向總監彙報,加薪額度超過總監權力範圍,須要向總經理彙報;
  • 員工還能夠提交請加申請,經理能夠決定2天如下的假,總監能夠決定5天如下的假,其他都要上報總經理;

基礎版本

class Request():
    
    def __init__(self):
        self.type = None  # 申請類型
        self.content = None  # 申請內容
        self.number = 0  # 申請數量
    
    
class Manager():
    
    def __init__(self, name):
        self.name = name
        
    def get_result(self, manager_level, request):
        if manager_level == "經理":
            if request.type == "請假" and request.number <=2:
                print("{}:{} 數量 {} 被批准".format(self.name, request.content, request.number))
            else:
                print("{}:{} 數量 {} 我無權處理".format(self.name, request.content, request.number))
        elif manager_level == "總監":
            if request.type == "請假" and request.number <=5:
                print("{}:{} 數量 {} 被批准".format(self.name, request.content, request.number))
            else:
                print("{}:{} 數量 {} 我無權處理".format(self.name, request.content, request.number))
        elif manager_level == "總經理":
            if request.type == "請假":
                print("{}:{} 數量 {} 被批准".format(self.name, request.content, request.number))
            elif request.type == "加薪" and request.number <= 500:
                print("{}:{} 數量 {} 被批准".format(self.name, request.content, request.number))
            elif request.type == "加薪" and request.number > 500:
                print("{}:{} 數量 {} 再說吧".format(self.name, request.content, request.number))
        
def main():
    jingli = Manager("經理")
    zongjian = Manager("總監")
    zongjingli = Manager("總經理")
    
    request = Request()
    request.type = "加薪"
    request.content = "賀賀請求加薪"
    request.number = 1000
    
    jingli.get_result(jingli.name, request)
    zongjian.get_result(zongjian.name, request)
    zongjingli.get_result(zongjingli.name, request)
    
    request.type = "請假"
    request.content = "賀賀請求請假"
    request.number = 3
    
    jingli.get_result(jingli.name, request)
    zongjian.get_result(zongjian.name, request)
    zongjingli.get_result(zongjingli.name, request)
    
main()
經理:賀賀請求加薪 數量 1000 我無權處理
總監:賀賀請求加薪 數量 1000 我無權處理
總經理:賀賀請求加薪 數量 1000 再說吧
經理:賀賀請求請假 數量 3 我無權處理
總監:賀賀請求請假 數量 3 被批准
總經理:賀賀請求請假 數量 3 被批准

點評

  • Manager類的get_result方法比較長,有太多的分支判斷,不是好的設計;
  • Mangeer類有太多的責任,違背了單一職責的原則,增長新的管理者,須要修改這個類,違背了開放封閉原則;

職責鏈模式

職責鏈模式,使得多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這個對象連成一條鏈,並沿着這條鏈傳遞該請求,知道有一個對象處理它爲止[DP]。github

職責鏈模式基本結構

from abc import ABCMeta, abstractmethod


class Handler():
    __metaclass__ = ABCMeta
    
    def __init__(self):
        self.successor = None  # 設置繼任者
        
    @abstractmethod
    def handle_request(self, request):
        pass
    
    
class ConcretHandler1(Handler):
    """
    處理0-10的請求
    """
    def handle_request(self, request):
        if request >=0 and request < 10:
            print("handler1 handle request [ {} ]".format(request))
        elif self.successor != None:  # 由繼任者處理請求
            self.successor.handle_request(request)
            

class ConcretHandler2(Handler):
    """
    處理10-20的請求
    """
    def handle_request(self, request):
        if request >=10 and request < 20:
            print("handler2 handle request [ {} ]".format(request))
        elif self.successor != None:  # 由繼任者處理請求
            self.successor.handle_request(request)
            

class ConcretHandler3(Handler):
    """
    處理20-30的請求
    """
    def handle_request(self, request):
        if request >=20 and request < 30:
            print("handler3 handle request [ {} ]".format(request))
        elif self.successor != None:  # 由繼任者處理請求
            self.successor.handle_request(request)


def main():
    h1 = ConcretHandler1()
    h2 = ConcretHandler2()
    h3 = ConcretHandler3()
    
    h1.successor = h2
    h2.successor = h3
    
    requests = [2, 5, 14, 22, 18, 3, 27, 20]
    
    for i in requests:
        h1.handle_request(i)
        
main()
handler1 handle request [ 2 ]
handler1 handle request [ 5 ]
handler2 handle request [ 14 ]
handler3 handle request [ 22 ]
handler2 handle request [ 18 ]
handler1 handle request [ 3 ]
handler3 handle request [ 27 ]
handler3 handle request [ 20 ]

點評

  • 當客戶提交一個請求時,請求是沿着職責鏈傳遞直至有一個ConcretHandler對象負責處理它
  • 接收者和發送者都沒有對方的明確信息,且鏈中的對象本身也並不知道鏈的結構
  • 職責鏈能夠簡化對象的相互連接,它們僅需保持一個指向其後繼者的引用,而不需保持它全部的候選接收者的引用
  • 能夠隨時增長或修改處理一個請求的結構,加強了給對象指派職責的靈活性
  • 一個請求極有可能到了鏈的末端都得不處處理,或者由於沒有正確配置而得不處處理
  • 最重要的兩點
    • 須要實現給每一個具體管理者設置它的上司,也就是它的後繼者
    • 須要在每一個具體管理者類處理請求時,作出判斷,是能夠處理請求,仍是必須「推卸責任」,轉移到後繼者

職責鏈模式——加薪代碼

from abc import ABCMeta, abstractmethod


class Manager():
    
    __metaclass__ = ABCMeta
    
    def __init__(self, name):
        self.name = name
        self.successor = None
        
    @abstractmethod
    def handle_request(self, request):
        pass
    

class CommonManager(Manager):
    
    def handle_request(self, request):
        if request.type == "請假" and request.number <=2:
            print("{}:{} 數量 {} 被批准".format(self.name, request.content, request.number))
        elif self.successor != None:
            self.successor.handle_request(request)
            
            
class Majordomo(Manager):
    def handle_request(self, request):
        if request.type == "請假" and request.number <=5:
            print("{}:{} 數量 {} 被批准".format(self.name, request.content, request.number))
        elif self.successor != None:
            self.successor.handle_request(request)

        
class GeneralManager(Manager):
    def handle_request(self, request):
        if request.type == "請假":
            print("{}:{} 數量 {} 被批准".format(self.name, request.content, request.number))
        elif request.type == "加薪" and request.number <= 500:
            print("{}:{} 數量 {} 被批准".format(self.name, request.content, request.number))
        elif request.type == "加薪" and request.number > 500:
            print("{}:{} 數量 {} 再說吧".format(self.name, request.content, request.number))
            
            
def main():
    jingli = CommonManager("經理")
    zongjian = Majordomo("總監")
    zongjingli = GeneralManager("總經理")
    
    jingli.successor = zongjian
    zongjian.successor = zongjingli
    
    request = Request()
    request.type = "加薪"
    request.content = "賀賀請求加薪"
    request.number = 1000
    
    jingli.handle_request(request)
    
    request.type = "請假"
    request.content = "賀賀請求請假"
    request.number = 3
    
    jingli.handle_request(request)
    
main()
總經理:賀賀請求加薪 數量 1000 再說吧
總監:賀賀請求請假 數量 3 被批准

職責鏈模式和狀態模式

  • 職責鏈模式,主要處理requet和handler的問題,當handler收到requet時,判斷是否本身是否能夠處理,處理邏輯在handler中;
  • 狀態模式,主要處理state和context的問題,當state變化時,改變context的state,繼續調用context的處理邏輯,處理邏輯在context中;
相關文章
相關標籤/搜索