1. 職責鍊模式概述
職責鍊模式: 避免請求發送者和接收者耦合在一起, 讓多個對象都有可能接收請求, 将這些對象連接配接成一條鍊, 并且沿着鍊傳遞請求, 直到有對象處理它為止. 職責鍊模式是一種對象行為型模式.
類圖如下所示:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuQmY1QzY1EWOxUjYmhzY1IzLcFzN1cjN18CXt92YucWbpBnYuEDcvw1LcpDc0RHaiojIsJye.png)
職責鍊模式結構圖中包含如下幾個角色:
- Handler(抽象處理者): 它定義一個處理請求的接口, 一般設計為抽象類, 由于不同的具體處理者處理請求的方式不同, 是以在其中定義抽象處理方法. 因為每個處理者的下家還有一個處理者, 是以在抽象處理者中定義了一個抽象處理者類型的對象, 作為其下家的引用. 通過該引用, 處理者可以形成一條鍊.
- ConcreateHandler(具體處理者): 它是一個抽象處理者的子類, 可以處理使用者請求, 在具體處理者類中實作了抽象處理者中定義的抽象請求處理方法, 在處理請求之前需要先做判斷, 看是否符合相應的處理權限, 如果可以處理請求就處理它, 如果不能就轉發給後繼者, 在具體處理者中可以通路鍊中的下一個對象, 以便轉發請求.
在職責鍊模式中, 很多對象由每一個對象對其下架的引用而連接配接起來形成一條鍊條. 請求在這個鍊條上傳遞, 直到鍊上某一個對象決定處理此請求. 送出請求的用戶端并不需要鍊條上的哪一個對象最終處理了這個請求, 這使得系統可以在不影響用戶端的情況下動态的重新組織鍊條和配置設定責任.
職責鍊模式并不建立職責鍊,職責鍊的建立工作必須由系統的其他部分來完成,一般是在使用該職責鍊的用戶端中建立職責鍊。職責鍊模式降低了請求的發送端和接收端之間的耦合,使多個對象都有機會處理這個請求。
2. Swift實作的一個demo
找個例子實作一下吧: Sunny軟體公司承接了某企業SCM(Supply Chain Management,供應鍊管理)系統的開發任務,其中包含一個采購審批子系統。該企業的采購審批是分級進行的,即根據采購金額的不同由不同層次的主管人員來審批,主任可以審批5萬元以下(不包括5萬元)的采購單,副董事長可以審批5萬元至10萬元(不包括10萬元)的采購單,董事長可以審批10萬元至50萬元(不包括50萬元)的采購單,50萬元及以上的采購單就需要開董事會讨論決定。
/// 抽象處理者
class Apporver: NSObject {
var apporver: Apporver?
var name: String
lazy var limitAmount: Double = 0
init(name: String) {
self.name = name
}
func processRequest(request: PurchaseRequest) {
}
}
/// 具體處理者
class ApporverA: Apporver {
override init(name: String) {
super.init(name: name)
self.limitAmount = 5000.0
}
override func processRequest(request: PurchaseRequest) {
if let productPrice = request.productPrice,
let productName = request.productName,
let productNumber = request.productNumber {
if productPrice < limitAmount {
print("主任\(name)審批采購單:\(productNumber),金額:\(productPrice)元,采購商品:\(productName)")
}else{
apporver?.processRequest(request: request)
}
}else{
print("購買單填寫不完整, 請重新填寫");
}
}
}
/// 具體處理者
class ApporverB: Apporver {
override init(name: String) {
super.init(name: name)
self.limitAmount = 10000.0
}
override func processRequest(request: PurchaseRequest) {
if let productPrice = request.productPrice,
let productName = request.productName,
let productNumber = request.productNumber {
if productPrice < limitAmount {
print("經理\(name)審批采購單:\(productNumber),金額:\(productPrice)元,采購商品:\(productName)")
}else{
apporver?.processRequest(request: request)
}
}else{
print("購買單填寫不完整, 請重新填寫");
}
}
}
/// 具體處理者
class ApporverC: Apporver {
override init(name: String) {
super.init(name: name)
self.limitAmount = 50000.0
}
override func processRequest(request: PurchaseRequest) {
if let productPrice = request.productPrice,
let productName = request.productName,
let productNumber = request.productNumber {
if productPrice < limitAmount {
print("CEO\(name)審批采購單:\(productNumber),金額:\(productPrice)元,采購商品:\(productName)")
}else{
apporver?.processRequest(request: request)
}
}else{
print("購買單填寫不完整, 請重新填寫");
}
}
}
/// 具體處理者
class ApporverD: Apporver {
override init(name: String) {
super.init(name: name)
self.limitAmount = 100000.0
}
override func processRequest(request: PurchaseRequest) {
if let productPrice = request.productPrice,
let productName = request.productName,
let productNumber = request.productNumber {
if productPrice < limitAmount {
print("董事會\(name)審批采購單:\(productNumber),金額:\(productPrice)元,采購商品:\(productName)")
}else{
apporver?.processRequest(request: request)
}
}else{
print("購買單填寫不完整, 請重新填寫");
}
}
}
/// 商品資訊的model
class PurchaseRequest: NSObject {
var productName: String?
var productNumber: String?
var productPrice: Double?
init(name: String, number: String, price: Double) {
productName = name
productNumber = number
productPrice = price
}
}
/// 用戶端代碼
// 生成一個職責鍊
let apporverA = ApporverA(name: "韋東方")
let apporverB = ApporverB(name: "成浩")
let apporverC = ApporverC(name: "劉勇")
let apporverD = ApporverD(name: "勝利")
apporverA.apporver = apporverB
apporverB.apporver = apporverC
apporverC.apporver = apporverD
let r1 = PurchaseRequest(name: "原子筆", number: "00001", price: 1000)
let r2 = PurchaseRequest(name: "桌子", number: "00002", price: 8000)
let r3 = PurchaseRequest(name: "電腦", number: "00003", price: 20000)
let r4 = PurchaseRequest(name: "茶杯", number: "00005", price: 60000)
apporverA.processRequest(request: r1)
apporverA.processRequest(request: r2)
apporverA.processRequest(request: r3)
apporverA.processRequest(request: r4)
結果:
3. 純與不純的職責鍊模式
3.1 純的職責鍊模式
一個純的職責鍊模式要求一個具體處理者對象隻能在兩個行為中選擇一個:要麼承擔全部責任,要麼将責任推給下家,不允許出現某一個具體處理者對象在承擔了一部分或全部責任後又将責任向下傳遞的情況。而且在純的職責鍊模式中,要求一個請求必須被某一個處理者對象所接收,不能出現某個請求未被任何一個處理者對象處理的情況。在前面的采購單審批執行個體中應用的是純的職責鍊模式。
3.2 不純的職責鍊模式
在一個不純的職責鍊模式中允許某個請求被一個具體處理者部分處理後再向下傳遞,或者一個具體處理者處理完某請求後其後繼處理者可以繼續處理該請求,而且一個請求可以最終不被任何處理者對象所接收。
4. 職責鍊模式的總結
職責鍊模式通過建立一條鍊來組織請求的處理者,請求将沿着鍊進行傳遞,請求發送者無須知道請求在何時、何處以及如何被處理,實作了請求發送者與處理者的解耦。在軟體開發中,如果遇到有多個對象可以處理同一請求時可以應用職責鍊模式,例如在Web應用開發中建立一個過濾器(Filter)鍊來對請求資料進行過濾,在工作流系統中實作公文的分級審批等等,使用職責鍊模式可以較好地解決此類問題。
4.1 主要優點
- 職責鍊模式使得一個對象無須知道是其他哪一個對象處理其請求,對象僅需知道該請求會被處理即可,接收者和發送者都沒有對方的明确資訊,且鍊中的對象不需要知道鍊的結構,由用戶端負責鍊的建立,降低了系統的耦合度。
- 請求處理對象僅需維持一個指向其後繼者的引用,而不需要維持它對所有的候選處理者的引用,可簡化對象的互相連接配接。
- 在給對象分派職責時,職責鍊可以給我們更多的靈活性,可以通過在運作時對該鍊進行動态的增加或修改來增加或改變處理一個請求的職責。
- 在系統中增加一個新的具體請求處理者時無須修改原有系統的代碼,隻需要在用戶端重建立鍊即可,從這一點來看是符合“開閉原則”的。
4.2 主要缺點
- 由于一個請求沒有明确的接收者,那麼就不能保證它一定會被處理,該請求可能一直到鍊的末端都得不到處理;一個請求也可能因職責鍊沒有被正确配置而得不到處理。
- 對于比較長的職責鍊,請求的處理可能涉及到多個處理對象,系統性能将受到一定影響,而且在進行代碼調試時不太友善。
- 如果建鍊不當,可能會造成循環調用,将導緻系統陷入死循環。
4.3 适用場景
- 有多個對象可以處理同一個請求,具體哪個對象處理該請求待運作時刻再确定,用戶端隻需将請求送出到鍊上,而無須關心請求的處理對象是誰以及它是如何處理的。
- 在不明确指定接收者的情況下,向多個對象中的一個送出一個請求。
- 可動态指定一組對象處理請求,用戶端可以動态建立職責鍊來處理請求,還可以改變鍊中處理者之間的先後次序。
Reference: http://blog.csdn.net/lovelion/article/details/7420891
版權聲明:本文為CSDN部落客「weixin_34242658」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。
原文連結:https://blog.csdn.net/weixin_34242658/article/details/92429454