美文网首页
行为模式-责任链模式(The Chain of Responsi

行为模式-责任链模式(The Chain of Responsi

作者: ZhouMac | 来源:发表于2016-05-10 22:42 被阅读262次

    本文大部分内容翻译至《Pro Design Pattern In Swift》By Adam Freeman,一些地方做了些许修改,并将代码升级到了Swift2.0,翻译不当之处望多包涵。

    责任链模式(The Chain of ResponsibilityPattern)

    在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。


    示例工程

    Xcode Command Line Tool 工程:

    Message.swift

    struct Message {
        let from:String
        let to:String
        let subject:String
    }
    

    我们定义了一个结构体Message,接下来我们定义发送Message的Transmitters:

    Transmitters.swift

    class LocalTransmitter {
        func sendMessage(message: Message) {
            print("Message to \(message.to) sent locally")
        }
    }
    
    class RemoteTransmitter {
        func sendMessage(message: Message) {
            print("Message to \(message.to) sent remotely")
        }
    }
    

    可以看出我们定义了两个代表发送信息的类,一个本地和一个远程。它们都有一个sendMessage方法,用来模拟发送信息。

    main.swift

    let messages = [
        Message(from: "bob@example.com", to: "joe@example.com",subject: "Free for lunch?"),
        Message(from: "joe@example.com", to: "alice@acme.com",subject: "New Contracts"),
        Message(from: "pete@example.com", to: "all@example.com",subject: "Priority: All-Hands Meeting")
    ]
    
    let localT = LocalTransmitter()
    let remoteT = RemoteTransmitter()
    
    for msg in messages {
    if let index = msg.from.characters.indexOf("@"){
        if (msg.to.hasSuffix(msg.from[Range<String.Index>(start:
        index, end: msg.from.endIndex)])) {
        localT.sendMessage(msg)
    } else {
        remoteT.sendMessage(msg)
        }
    } else {
        print("Error: cannot send message to \(msg.from)")
        }
    }
    

    可以看到如果from和to如果有相同的后缀,那么就调用本地发送方法;如果后缀不同,则调用远程发送方法。运行程序,得到下面的输出:

    Message to joe@example.com sent locally
    Message to alice@acme.com sent remotely
    Message to all@example.com sent locally
    

    理解责任链模式解决的问题

    示例中存在的问题是使用transmitter类来发送消息的组件必须知道应该用哪一个类发送(本地还是远程)。如果要增加新的发送方式,这将变得十分困难。假如我们要增加一个优先发送方式,那么将作如下十分蛋疼的修改:

    Transmitters.swift

    class LocalTransmitter {
        func sendMessage(message: Message) {
            print("Message to \(message.to) sent locally")
        }
    }
    
    class RemoteTransmitter {
        func sendMessage(message: Message) {
            print("Message to \(message.to) sent remotely")
        }
    }
    
    class PriorityTransmitter {
        func sendMessage(message: Message) {
            print("Message to \(message.to) sent as priority")
        }
    }
    

    main.swift

    let messages = [
        Message(from: "bob@example.com", to: "joe@example.com",
        subject: "Free for lunch?"),
        Message(from: "joe@example.com", to: "alice@acme.com",
        subject: "New Contracts"),
        Message(from: "pete@example.com", to: "all@example.com",
        subject: "Priority: All-Hands Meeting"),
    ]
    
    let localT = LocalTransmitter()
    let remoteT = RemoteTransmitter()
    let priorityT = PriorityTransmitter()
    
    for msg in messages {
        if (msg.subject.hasPrefix("Priority")) {
            priorityT.sendMessage(msg)
        }else if let index = msg.from.characters.indexOf("@"){
            if (msg.to.hasSuffix(msg.from[Range<String.Index>(start:
                index, end: msg.from.endIndex)])) {
                localT.sendMessage(msg)
            } else {
                remoteT.sendMessage(msg)
            }
        } else {
            print("Error: cannot send message to \(msg.from)")
        }
    }
    

    运行程序:

    Message to joe@example.com sent locally
    Message to alice@acme.com sent remotely
    Message to all@example.com sent as priority
    

    理解责任链模式

    责任链模式通过将所有的transmitters 放在一个链里面来解决这个问题。每一个环都在链里并且检查Message对象来决定是否承担责任。如果链里的某一个环能够处理Message对象,那么它处理。如果不能,请求传递到下一个环。这个过程一直持续到有环处理或者到了链中最后一个环。



    实现责任链模式

    这里我们用定义一个拥有可选类型属性来代表链中下一个环的基类。

    Transmitters.swift

    class Transmitter {
        var nextLink:Transmitter?
        
        required init() {}
        
        func sendMessage(message:Message) {
            if (nextLink != nil) {
                nextLink!.sendMessage(message);
            } else {
                print("End of chain reached. Message not sent");
            }
        }
        
        private class func matchEmailSuffix(message:Message) -> Bool {
            if let index = message.from.characters.indexOf("@") {
                return message.to.hasSuffix(message.from[Range<String.Index>(start:
                    index, end: message.from.endIndex)]);
            }
            return false
        }
    }
    
    class LocalTransmitter : Transmitter {
        override func sendMessage(message: Message) {
            if (Transmitter.matchEmailSuffix(message)) {
                print("Message to \(message.to) sent locally")
            } else {
                super.sendMessage(message)
            }
        }
    }
    
    class RemoteTransmitter : Transmitter {
        override func sendMessage(message: Message) {
            if (!Transmitter.matchEmailSuffix(message)) {
                print("Message to \(message.to) sent remotely")
            } else {
                super.sendMessage(message)
            }
        }
    }
    
    class PriorityTransmitter : Transmitter {
        override func sendMessage(message: Message) {
            if (message.subject.hasPrefix("Priority")) {
                print("Message to \(message.to) sent as priority")
            } else {
                super.sendMessage(message)
            }
        }
    }
    

    Transmitter 类定义了发送器的基本行为,包括了提交请求到链中下一个环。初始化方法前面的required关键字使得我们可以用类型来创建 transmitter实例。

    创建和提供责任链

    下一步我们将创建责任链:

    Transmitters.swift

    ......
    class Transmitter {
        var nextLink:Transmitter?
        
        required init() {}
        
        func sendMessage(message:Message) {
            if (nextLink != nil) {
                nextLink!.sendMessage(message);
            } else {
                print("End of chain reached. Message not sent");
            }
        }
        
        private class func matchEmailSuffix(message:Message) -> Bool {
            if let index = message.from.characters.indexOf("@") {
                return message.to.hasSuffix(message.from[Range<String.Index>(start:
                    index, end: message.from.endIndex)]);
            }
            return false
        }
        
        class func createChain() -> Transmitter? {
            let transmitterClasses:[Transmitter.Type] = [
                PriorityTransmitter.self,
                LocalTransmitter.self,
                RemoteTransmitter.self
            ]
            
            var link:Transmitter?
            
            for tClass in transmitterClasses.reverse() {
                let existingLink = link
                link = tClass.init()
                link?.nextLink = existingLink
            }
            return link
        }
    }
    ......
    

    应用责任链模式

    main.swift

    let messages = [
        Message(from: "bob@example.com", to: "joe@example.com",
        subject: "Free for lunch?"),
        Message(from: "joe@example.com", to: "alice@acme.com",
        subject: "New Contracts"),
        Message(from: "pete@example.com", to: "all@example.com",
        subject: "Priority: All-Hands Meeting"),
    ]
    
    if let chain = Transmitter.createChain() {
            for msg in messages {
                chain.sendMessage(msg)
            }
    }
    

    运行程序:

    Message to joe@example.com sent locally
    Message to alice@acme.com sent remotely
    Message to all@example.com sent as priority
    

    责任链模式的变形

    这里有几种比较常用的变形,我们一一介绍。

    应用工厂方法模式

    我们可以将责任链模式工厂方法模式或者抽象工厂方法模式结合起来,可以满足不同的请求。

    Transmitters.swift

    .....
        class func createChain(localOnly:Bool) -> Transmitter? {
            let transmitterClasses:[Transmitter.Type] = localOnly ? [PriorityTransmitter.self, LocalTransmitter.self]
            : [PriorityTransmitter.self, LocalTransmitter.self, RemoteTransmitter.self]
            
            var link:Transmitter?
            
            for tClass in transmitterClasses.reverse() {
                let existingLink = link
                link = tClass.init()
                link?.nextLink = existingLink
            }
            return link
        }
    ......
    

    可以看出我们增加了一个只有本地发送的链。

    main.swift

    let messages = [
        Message(from: "bob@example.com", to: "joe@example.com",
        subject: "Free for lunch?"),
        Message(from: "joe@example.com", to: "alice@acme.com",
        subject: "New Contracts"),
        Message(from: "pete@example.com", to: "all@example.com",
        subject: "Priority: All-Hands Meeting"),
    ]
    
    if let chain = Transmitter.createChain(true) {
            for msg in messages {
                chain.sendMessage(msg)
            }
    }
    

    运行程序,可以看出远程发送的情况有所不同:

    Message to joe@example.com sent locally
    End of chain reached. Message not sent
    Message to all@example.com sent as priority
    

    表面请求是否被接受

    现在,请求组件并不清楚请求是否被接受,我们将对此做修改。

    Transmitters.swift

    class Transmitter {
        var nextLink:Transmitter?
        
        required init() {}
        
        func sendMessage(message:Message) -> Bool{
            if (nextLink != nil) {
               return nextLink!.sendMessage(message)
            
            } else {
                print("End of chain reached. Message not sent")
                return false
            }
        }
        
        private class func matchEmailSuffix(message:Message) -> Bool {
            if let index = message.from.characters.indexOf("@") {
                return message.to.hasSuffix(message.from[Range<String.Index>(start:
                    index, end: message.from.endIndex)])
            }
            return false
        }
        
        class func createChain(localOnly:Bool) -> Transmitter? {
            let transmitterClasses:[Transmitter.Type] = localOnly ? [PriorityTransmitter.self, LocalTransmitter.self]
            : [PriorityTransmitter.self, LocalTransmitter.self, RemoteTransmitter.self]
            
            var link:Transmitter?
            
            for tClass in transmitterClasses.reverse() {
                let existingLink = link
                link = tClass.init()
                link?.nextLink = existingLink
            }
            return link
        }
    }
    
    class LocalTransmitter : Transmitter {
        override func sendMessage(message: Message) ->Bool{
            if (Transmitter.matchEmailSuffix(message)) {
                print("Message to \(message.to) sent locally")
                return true
            } else {
                return super.sendMessage(message)
            }
        }
    }
    
    class RemoteTransmitter : Transmitter {
        override func sendMessage(message: Message) ->Bool{
            if (!Transmitter.matchEmailSuffix(message)) {
                print("Message to \(message.to) sent remotely")
                return true
            } else {
                return super.sendMessage(message)
            }
        }
    }
    
    class PriorityTransmitter : Transmitter {
        override func sendMessage(message: Message) ->Bool{
            if (message.subject.hasPrefix("Priority")) {
                print("Message to \(message.to) sent as priority")
                return true
            } else {
                return super.sendMessage(message)
            }
        }
    }
    

    接下来修改main.swift:

    let messages = [
        Message(from: "bob@example.com", to: "joe@example.com",
        subject: "Free for lunch?"),
        Message(from: "joe@example.com", to: "alice@acme.com",
        subject: "New Contracts"),
        Message(from: "pete@example.com", to: "all@example.com",
        subject: "Priority: All-Hands Meeting"),
    ]
    
    if let chain = Transmitter.createChain(true) {
        for msg in messages {
            let handled = chain.sendMessage(msg)
            print("Message sent: \(handled)")
        }
    }
    

    运行程序:

    Message to joe@example.com sent locally
    Message sent: true
    End of chain reached. Message not sent
    Message sent: false
    Message to all@example.com sent as priority
    Message sent: true
    

    通知链中所有的环

    在标准的责任链模式中,责任环前面所有的环都被请求过,责任环后面的环则不会被请求。这里我们将请求所有的环,无论责任环是否已经被执行。

    Transmitters.swift

    class Transmitter {
        var nextLink:Transmitter?
        
        required init() {}
        
        func sendMessage(message:Message,handled: Bool = false) -> Bool{
            if (nextLink != nil) {
               return nextLink!.sendMessage(message,handled: handled)
            
            } else if(!handled) {
                print("End of chain reached. Message not sent")
            }
            return handled
        }
        
        private class func matchEmailSuffix(message:Message) -> Bool {
            if let index = message.from.characters.indexOf("@") {
                return message.to.hasSuffix(message.from[Range<String.Index>(start:
                    index, end: message.from.endIndex)])
            }
            return false
        }
        
        class func createChain(localOnly:Bool) -> Transmitter? {
            let transmitterClasses:[Transmitter.Type] = localOnly ? [PriorityTransmitter.self, LocalTransmitter.self]
            : [PriorityTransmitter.self, LocalTransmitter.self, RemoteTransmitter.self]
            
            var link:Transmitter?
            
            for tClass in transmitterClasses.reverse() {
                let existingLink = link
                link = tClass.init()
                link?.nextLink = existingLink
            }
            return link
        }
    }
    
    class LocalTransmitter : Transmitter {
        override func sendMessage(message: Message, var handled:Bool) ->Bool{
            if (!handled && Transmitter.matchEmailSuffix(message)) {
                print("Message to \(message.to) sent locally")
                handled = true
            }
            return super.sendMessage(message, handled: handled)
        }
    }
    
    class RemoteTransmitter : Transmitter {
        override func sendMessage(message: Message, var handled:Bool) ->Bool{
            if (!handled && !Transmitter.matchEmailSuffix(message)) {
                print("Message to \(message.to) sent remotely")
                handled = true
            }
            return super.sendMessage(message, handled: handled)
        }
    }
    
    class PriorityTransmitter : Transmitter {
        var totalMessages = 0
        var handledMessages = 0
        
        override func sendMessage(message: Message, var handled:Bool) -> Bool {
            totalMessages++
            if (!handled && message.subject.hasPrefix("Priority")) {
                handledMessages++
                print("Message to \(message.to) sent as priority")
                print("Stats: Handled \(handledMessages) of \(totalMessages)")
                handled = true
            }
            return super.sendMessage(message, handled: handled)
        }
    }
    

    运行程序:

    Message to joe@example.com sent locallyMessage 
    sent: trueEnd of chain reached. 
    Message not sentMessage 
    sent: false
    Message to all@example.com sent as priority
    Stats: Handled 1 of 3
    Message sent: true
    

    相关文章

      网友评论

          本文标题:行为模式-责任链模式(The Chain of Responsi

          本文链接:https://www.haomeiwen.com/subject/rspyrttx.html