本文大部分內(nèi)容翻譯至《Pro Design Pattern In Swift》By Adam Freeman癌瘾,一些地方做了些許修改诀诊,并將代碼升級(jí)到了Swift2.0,翻譯不當(dāng)之處望多包涵。
責(zé)任鏈模式(The Chain of ResponsibilityPattern)
在責(zé)任鏈模式里藐握,很多對(duì)象由每一個(gè)對(duì)象對(duì)其下家的引用而連接起來形成一條鏈。請(qǐng)求在這個(gè)鏈上傳遞,直到鏈上的某一個(gè)對(duì)象決定處理此請(qǐng)求袜蚕。發(fā)出這個(gè)請(qǐng)求的客戶端并不知道鏈上的哪一個(gè)對(duì)象最終處理這個(gè)請(qǐng)求,這使得系統(tǒng)可以在不影響客戶端的情況下動(dòng)態(tài)地重新組織和分配責(zé)任绢涡。
示例工程
Xcode Command Line Tool 工程:
Message.swift
struct Message {
let from:String
let to:String
let subject:String
}
我們定義了一個(gè)結(jié)構(gòu)體Message牲剃,接下來我們定義發(fā)送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")
}
}
可以看出我們定義了兩個(gè)代表發(fā)送信息的類,一個(gè)本地和一個(gè)遠(yuǎn)程垂寥。它們都有一個(gè)sendMessage方法颠黎,用來模擬發(fā)送信息另锋。
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如果有相同的后綴,那么就調(diào)用本地發(fā)送方法狭归;如果后綴不同夭坪,則調(diào)用遠(yuǎn)程發(fā)送方法。運(yùn)行程序过椎,得到下面的輸出:
Message to joe@example.com sent locally
Message to alice@acme.com sent remotely
Message to all@example.com sent locally
理解責(zé)任鏈模式解決的問題
示例中存在的問題是使用transmitter類來發(fā)送消息的組件必須知道應(yīng)該用哪一個(gè)類發(fā)送(本地還是遠(yuǎn)程)室梅。如果要增加新的發(fā)送方式,這將變得十分困難疚宇。假如我們要增加一個(gè)優(yōu)先發(fā)送方式亡鼠,那么將作如下十分蛋疼的修改:
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)")
}
}
運(yùn)行程序:
Message to joe@example.com sent locally
Message to alice@acme.com sent remotely
Message to all@example.com sent as priority
理解責(zé)任鏈模式
責(zé)任鏈模式通過將所有的transmitters 放在一個(gè)鏈里面來解決這個(gè)問題。每一個(gè)環(huán)都在鏈里并且檢查Message對(duì)象來決定是否承擔(dān)責(zé)任敷待。如果鏈里的某一個(gè)環(huán)能夠處理Message對(duì)象间涵,那么它處理。如果不能榜揖,請(qǐng)求傳遞到下一個(gè)環(huán)勾哩。這個(gè)過程一直持續(xù)到有環(huán)處理或者到了鏈中最后一個(gè)環(huán)。
實(shí)現(xiàn)責(zé)任鏈模式
這里我們用定義一個(gè)擁有可選類型屬性來代表鏈中下一個(gè)環(huán)的基類举哟。
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 類定義了發(fā)送器的基本行為思劳,包括了提交請(qǐng)求到鏈中下一個(gè)環(huán)。初始化方法前面的required關(guān)鍵字使得我們可以用類型來創(chuàng)建 transmitter實(shí)例妨猩。
創(chuàng)建和提供責(zé)任鏈
下一步我們將創(chuàng)建責(zé)任鏈:
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
}
}
......
應(yīng)用責(zé)任鏈模式
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)
}
}
運(yùn)行程序:
Message to joe@example.com sent locally
Message to alice@acme.com sent remotely
Message to all@example.com sent as priority
責(zé)任鏈模式的變形
這里有幾種比較常用的變形潜叛,我們一一介紹。
應(yīng)用工廠方法模式
我們可以將責(zé)任鏈模式和工廠方法模式或者抽象工廠方法模式結(jié)合起來壶硅,可以滿足不同的請(qǐng)求威兜。
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
}
......
可以看出我們?cè)黾恿艘粋€(gè)只有本地發(fā)送的鏈。
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)
}
}
運(yùn)行程序,可以看出遠(yuǎn)程發(fā)送的情況有所不同:
Message to joe@example.com sent locally
End of chain reached. Message not sent
Message to all@example.com sent as priority
表面請(qǐng)求是否被接受
現(xiàn)在森瘪,請(qǐng)求組件并不清楚請(qǐng)求是否被接受牡属,我們將對(duì)此做修改。
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)")
}
}
運(yùn)行程序:
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
通知鏈中所有的環(huán)
在標(biāo)準(zhǔn)的責(zé)任鏈模式中扼睬,責(zé)任環(huán)前面所有的環(huán)都被請(qǐng)求過逮栅,責(zé)任環(huán)后面的環(huán)則不會(huì)被請(qǐng)求。這里我們將請(qǐng)求所有的環(huán)窗宇,無論責(zé)任環(huán)是否已經(jīng)被執(zhí)行措伐。
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)
}
}
運(yùn)行程序:
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