本文大部分内容翻译至《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: "[email protected]", to: "[email protected]",subject: "Free for lunch?"),
Message(from: "[email protected]", to: "[email protected]",subject: "New Contracts"),
Message(from: "[email protected]", to: "[email protected]",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(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 [email protected] sent locally
Message to [email protected] sent remotely
Message to [email protected] 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: "[email protected]", to: "[email protected]",
subject: "Free for lunch?"),
Message(from: "[email protected]", to: "[email protected]",
subject: "New Contracts"),
Message(from: "[email protected]", to: "[email protected]",
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(start:
index, end: msg.from.endIndex)])) {
localT.sendMessage(msg)
} else {
remoteT.sendMessage(msg)
}
} else {
print("Error: cannot send message to \(msg.from)")
}
}
运行程序:
Message to [email protected] sent locally
Message to [email protected] sent remotely
Message to [email protected] 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(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(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: "[email protected]", to: "[email protected]",
subject: "Free for lunch?"),
Message(from: "[email protected]", to: "[email protected]",
subject: "New Contracts"),
Message(from: "[email protected]", to: "[email protected]",
subject: "Priority: All-Hands Meeting"),
]
if let chain = Transmitter.createChain() {
for msg in messages {
chain.sendMessage(msg)
}
}
运行程序:
Message to [email protected] sent locally
Message to [email protected] sent remotely
Message to [email protected] 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: "[email protected]", to: "[email protected]",
subject: "Free for lunch?"),
Message(from: "[email protected]", to: "[email protected]",
subject: "New Contracts"),
Message(from: "[email protected]", to: "[email protected]",
subject: "Priority: All-Hands Meeting"),
]
if let chain = Transmitter.createChain(true) {
for msg in messages {
chain.sendMessage(msg)
}
}
运行程序,可以看出远程发送的情况有所不同:
Message to [email protected] sent locally
End of chain reached. Message not sent
Message to [email protected] 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(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: "[email protected]", to: "[email protected]",
subject: "Free for lunch?"),
Message(from: "[email protected]", to: "[email protected]",
subject: "New Contracts"),
Message(from: "[email protected]", to: "[email protected]",
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 [email protected] sent locally
Message sent: true
End of chain reached. Message not sent
Message sent: false
Message to [email protected] 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(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 [email protected] sent locallyMessage
sent: trueEnd of chain reached.
Message not sentMessage
sent: false
Message to [email protected] sent as priority
Stats: Handled 1 of 3
Message sent: true