设计模式-20.职责链模式

181 阅读2分钟

一句话总结

使多个对象都有机会处理请求,从而避免请求的发送者和接受者的耦合关系。将这些对象连成一条链,并沿着该链传递该请求,直到有一个对象处理它为止。

需求

公司的审批通常要经过组长、经理、总监、总经理层层审批,那么如何用代码实现这样一个逻辑呢?

Code V1.0

manager类的代码不符合单一职责原则和开放-封闭原则。

static func main() {
    let jingli = Manager(name: "经理")
    let zongjian = Manager(name: "总监")
    let zongjingli = Manager(name: "总经理")

    let request = Request()
    request.requestType = "加薪"
    request.requestContent = "小菜请求加薪"
    request.number = 1000

    jingli.getResult(managerLevel: "经理", request: request)
    zongjian.getResult(managerLevel: "总监", request: request)
    zongjingli.getResult(managerLevel: "总经理", request: request)

    let request2 = Request()
    request2.requestType = "请假"
    request2.requestContent = "小菜请求请假"
    request2.number = 3

    jingli.getResult(managerLevel: "经理", request: request2)
    zongjian.getResult(managerLevel: "总监", request: request2)
    zongjingli.getResult(managerLevel: "总经理", request: request2)
}

class Request {
    var requestType = ""
    var requestContent = ""
    var number = 0
}

class Manager {
    let name: String

    init(name: String) {
        self.name = name
    }

    func getResult(managerLevel: String, request: Request) {
        if managerLevel == "经理" {
            if request.requestType == "请假", request.number <= 2 {
                print("\(name): \(request.requestContent) 数量\(request.number)被批准")
            } else {
                print("\(name): \(request.requestContent) 数量\(request.number)我无权处理")
            }
        } else if managerLevel == "总监" {
            if request.requestType == "请假", request.number <= 5 {
                print("\(name): \(request.requestContent) 数量\(request.number)被批准")
            } else {
                print("\(name): \(request.requestContent) 数量\(request.number)我无权处理")
            }
        } else if managerLevel == "总经理" {
            if request.requestType == "请假" {
                print("\(name): \(request.requestContent) 数量\(request.number)被批准")
            } else if request.requestType == "加薪", request.number <= 500 {
                print("\(name): \(request.requestContent) 数量\(request.number)被批准")
            } else if request.requestType == "加薪", request.number > 500 {
                print("\(name): \(request.requestContent) 数量\(request.number)再说吧")
            }
        }
    }
}

职责链模式示例代码

当前一个类的实例处理不了的时候可以交由下一个类的实例去处理。

static func main() {
    let handler1 = ConcreteHandler1()
    let handler2 = ConcreteHandler2()
    let handler3 = ConcreteHandler3()

    handler1.successor = handler2
    handler2.successor = handler3

    let requests = [2, 8, 11, 14, 21, 23, 5, 30, 40]

    for item in requests {
        handler1.handleRequest(request: item)
    }
}

protocol Handler {
    var successor: Handler? { set get }
    func handleRequest(request: Int)
}

class ConcreteHandler1: Handler {
    var successor: Handler?

    func handleRequest(request: Int) {
        if request >= 0, request < 10 {
            print("\(Self.self) 处理请求 \(request)")
        } else {
            successor?.handleRequest(request: request)
        }
    }
}

class ConcreteHandler2: Handler {
    var successor: Handler?

    func handleRequest(request: Int) {
        if request >= 10, request < 20 {
            print("\(Self.self) 处理请求 \(request)")
        } else {
            successor?.handleRequest(request: request)
        }
    }
}

class ConcreteHandler3: Handler {
    var successor: Handler?

    func handleRequest(request: Int) {
        if request >= 20, request < 30 {
            print("\(Self.self) 处理请求 \(request)")
        } else {
            successor?.handleRequest(request: request)
        }
    }
}

Code V2.0

用职责链模式实现该需求。

static func main() {
    let jingli = CommonManager(name: "经理")
    let zongjian = Majordomo(name: "总监")
    let zongjingli = GeneralManager(name: "总经理")

    jingli.superior = zongjian
    zongjian.superior = zongjingli

    let request = Request()
    request.requestType = "加薪"
    request.requestContent = "小菜请求加薪"
    request.number = 1000

    jingli.requestApplications(request: request)

    let request2 = Request()
    request2.requestType = "请假"
    request2.requestContent = "小菜请求请假"
    request2.number = 3

    jingli.requestApplications(request: request2)
}

protocol Manager {
    var name: String { set get }
    var superior: Manager? { set get }
    
    func requestApplications(request: Request)
}

class Request {
    var requestType = ""
    var requestContent = ""
    var number = 0
}

class CommonManager: Manager {
    var name: String

    var superior: Manager?

    init(name: String) {
        self.name = name
    }

    func requestApplications(request: Request) {
        if request.requestType == "请假", request.number <= 2 {
            print("\(name): \(request.requestContent) 数量\(request.number)被批准")
        } else {
            superior?.requestApplications(request: request)
        }
    }
}

class Majordomo: Manager {
    var name: String

    var superior: Manager?

    init(name: String) {
        self.name = name
    }

    func requestApplications(request: Request) {
        if request.requestType == "请假", request.number <= 5 {
            print("\(name): \(request.requestContent) 数量\(request.number)被批准")
        } else {
            superior?.requestApplications(request: request)
        }
    }
}

class GeneralManager: Manager {
    var name: String

    var superior: Manager?

    init(name: String) {
        self.name = name
    }

    func requestApplications(request: Request) {
        if request.requestType == "请假" {
            print("\(name): \(request.requestContent) 数量\(request.number)被批准")
        } else if request.requestType == "加薪", request.number <= 500 {
            print("\(name): \(request.requestContent) 数量\(request.number)被批准")
        } else if request.requestType == "加薪", request.number > 500 {
            print("\(name): \(request.requestContent) 数量\(request.number)再说吧")
        }
    }
}

职责链模式的优点

  • 当客户提交一个请求时,请求会沿链传递,直到有一个对象去处理它。
  • 接受者和发送者都没有对方的明确信息,且链中的对象都不知道链的结构。可简化对象的相互连接,每个对象只需保持一个指向其后继者的引用,而无需保持全部后续者的引用。