Stone Bakery想要進一步快速發展,決定開始請教專家如何將工作流程優化甚至自動化,於是又找到了你和我。
我們從調查中發現,由於Stone Bakery幾乎每天都在進貨,而員工都會先代付費用之後再向店長確認費用報銷,於是店長幾乎每天都要處理報銷的問題,
我們認為店長可以下發權限,對於一些金額較小的費用可以直接讓其他人來做審核。
開發用於報銷費用的系統
我們建立了ConfirmPayment,並且在裡面設立了三種職位的報銷方法。
通過Struct Paymen來規範報銷的格式,需要有報銷人、金額、用途。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
struct Payment { let name:String let amount:Int let usage:String } class TeamLeader { func confirm(payment:Payment) { if payment.amount <= 1000 { print("Team Leader 同意了 \(payment.name) 用來 \(payment.usage) 的費用報銷,金額為: \(payment.amount)") } else { print("Team Leader: 這個費用不該找我審核吧?") } } } class Chef { func confirm(payment:Payment) { if payment.amount > 1000 && payment.amount < 10000 { print("Chef 同意了 \(payment.name) 用來 \(payment.usage) 的費用報銷,金額為: \(payment.amount)") } else { print("Chef: 這個費用不該找我審核吧?") } } } class Boss { func confirm(payment:Payment) { if payment.amount > 10000 && payment.amount < 100000 { print("Boss 同意了 \(payment.name) 用來 \(payment.usage) 的費用報銷,金額為: \(payment.amount)") } else { print("Boss: 請問\(payment.name) 這個用來 \(payment.usage) 用途是?") } } } |
之後Stone Bakery約定好,金額在1000以下的可以直接找Team Leader審核,1,000 ~ 10,000的可以找Chef審核,更大的金額才需要找店長Boss
我們來建立幾筆費用試試看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
let payments = [ Payment(name:"Don", amount:75000, usage:"購買麵包設備"), Payment(name:"Howard", amount:33000, usage:"購買高級調味料"), Payment(name:"Jerry", amount:7500, usage:"購買進口桿麵棍"), Payment(name:"Jack", amount:2500, usage:"購買麵粉"), Payment(name:"Oliver", amount:300, usage:"購買瓦斯"), Payment(name:"ES", amount:100000, usage:"購買生產線") ] let teamLeader = TeamLeader() let chef = Chef() let boss = Boss() for payment in payments { if payment.amount <= 1000 { teamLeader.confirm(payment: payment) } else if payment.amount < 10000 { chef.confirm(payment: payment) } else { boss.confirm(payment: payment) } } |
這下店長應該會輕鬆很多了~!
1 2 3 4 5 6 |
Boss 同意了 Don 用來 購買麵包設備 的費用報銷,金額為: 75000 Boss 同意了 Howard 用來 購買高級調味料 的費用報銷,金額為: 33000 Chef 同意了 Jerry 用來 購買進口桿麵棍 的費用報銷,金額為: 7500 Chef 同意了 Jack 用來 購買麵粉 的費用報銷,金額為: 2500 Team Leader 同意了 Oliver 用來 購買瓦斯 的費用報銷,金額為: 300 Boss: 請問ES 這個用來 購買生產線 用途是? |
不過似乎每次調用報銷系統都需要了解ConfirmPayment中具體的規則,比如10,000以上的費用就要找Boss,有沒有不需要了解具體實現方法就進行報銷的方法呢?
責任鏈模式(Chain of Responsibility Pattern)
責任鏈模式通過鏈式的方式將這些消息傳送類組織起來。
如果責任鏈上的某個鏈可以處理Paymen對象的請求,他就會承擔起這個責任。如果不能處理則會將請求傳遞給責任鏈上的下一個鏈,知道該請求得到相應或者到達責任鏈的盡頭。
責任鏈模式的關鍵在於對調用組件隱藏責任鏈上單個鏈的實現細節,而是用協議或者基類可以實現這樣的目的。v
我們建立一個Transmitter:
- 其中nextLink用來記錄下一個鏈。
- confirm方法中會判斷下一個鏈是否存在,如果有就交給下一個鏈,如果沒有就跳出走到尾端的提示
- createChain用來建立鏈條。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
class Transmitter { var nextLink:Transmitter? required init() {} func confirm(payment:Payment) { if nextLink != nil { nextLink?.confirm(payment: payment) } else { print("抵達責任鏈尾端,似乎用來 \(payment.usage) 的費用 沒有人可以處理") } } class func createChain() -> Transmitter? { let transmitterClasses:[Transmitter.Type] = [ TeamLeaderTransmitter.self, ChefTransmitter.self, BossTransmitter.self ] var link:Transmitter? for tClass in transmitterClasses { let existingLink = link link = tClass.init() link?.nextLink = existingLink } return link } } |
然後讓每一個鏈都繼承Transmitter。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
class TeamLeaderTransmitter: Transmitter { override func confirm(payment:Payment) { if payment.amount <= 1000 { print("Team Leader 同意了 \(payment.name) 用來 \(payment.usage) 的費用報銷,金額為: \(payment.amount)") } else { super.confirm(payment: payment) } } } class ChefTransmitter: Transmitter { override func confirm(payment:Payment) { if payment.amount > 1000 && payment.amount < 10000 { print("Chef 同意了 \(payment.name) 用來 \(payment.usage) 的費用報銷,金額為: \(payment.amount)") } else { super.confirm(payment: payment) } } } class BossTransmitter: Transmitter { override func confirm(payment: Payment) { if payment.amount > 10000 && payment.amount < 100000 { print("Boss 同意了 \(payment.name) 用來 \(payment.usage) 的費用報銷,金額為: \(payment.amount)") } else { super.confirm(payment: payment) } } } |
最後我們就可以做到在不了解具體審核機制的情況下直接調用方法了。
1 2 3 4 5 |
if let chain = Transmitter.createChain() { for payment in payments { chain.confirm(payment: payment) } } |
輸出結果:
1 2 3 4 5 6 |
Boss 同意了 Don 用來 購買麵包設備 的費用報銷,金額為: 75000 Boss 同意了 Howard 用來 購買高級調味料 的費用報銷,金額為: 33000 Chef 同意了 Jerry 用來 購買進口桿麵棍 的費用報銷,金額為: 7500 Chef 同意了 Jack 用來 購買麵粉 的費用報銷,金額為: 2500 Team Leader 同意了 Oliver 用來 購買瓦斯 的費用報銷,金額為: 300 抵達責任鏈尾端,似乎用來 購買生產線 的費用 沒有人可以處理 |
iOS App開發中的例子
Cocoa Touch中的事件處理流程中的響應者鏈,當使用者在設備上點擊屏幕時,首先會找到被點擊的View,如果該View不處理點擊事件,則會沿著響應鏈向上回溯,比如交給父類View來處理,如果不處理則繼續向上回溯直到有對象處理或者走到響應鏈的尾端因無人處理而忽略掉。
可以到github上看看這個責任鏈模式的例子。