Swift中设计模式的实践一:责任链模式

本文是对Design Patterns implemented in Swift 3.0的解读和翻译,通过这些案例对Swift中的设计模式进行总结和加深理解。
本文示例代码都是在Xcode的Playground上运行的。

什么是设计模式

设计模式(Design Patterns)是面向对象程序开发过程中总结出来的代码设计方式。设计模式为程序开发所遇到的各种情景提供了最佳解决方案,合理地运用设计模式,可以提高代码的复用性,降低代码的耦合度,提升程序的灵活度等等,从而有效的提高开发效率。

设计模式按功能大概可分为三类:

设计模式的浅析和实践

行为型模式

责任链模式(Chain Of Responsibility)

责任链模式用于处理不同的请求(request),每个请求会被不同的程序处理。
原理:为请求提供统一的方法,请求的接收者则根据不同的请求进行不同处理。多个可以接收请求的对象组成一条链,符合条件的接收者会对请求处理,不符合条件的接收者将请求传递给链的下一个接收者,直到链的最后。
目的:将请求者与接收者解耦,降低代码耦合度

示例说明:

ATM机中存在面额为100、50、20、10元的钞票若干,当向ATM查询是否可以提取任意金额现金时,ATM返回true或false。

示例:

import Swift
import Foundation


final class MoneyPile {

    let value: Int
    var quantity: Int
    var nextPile: MoneyPile?

    init(value: Int, quantity: Int, nextPile: MoneyPile?) {
        self.value = value
        self.quantity = quantity
        self.nextPile = nextPile
    }

    func canWithdraw(amount: Int) -> Bool {

        var amount = amount

        func canTakeSomeBill(want: Int) -> Bool {
            return (want / self.value) > 0
        }

        var quantity = self.quantity

        while canTakeSomeBill(want: amount) {

            if quantity == 0 {
                break
            }

            amount -= self.value
            quantity -= 1
        }

        guard amount > 0 else {
            return true
        }

        if let next = self.nextPile {
            return next.canWithdraw(amount: amount)
        }

        return false
    }
}

final class ATM {
    private var hundred: MoneyPile
    private var fifty: MoneyPile
    private var twenty: MoneyPile
    private var ten: MoneyPile

    private var startPile: MoneyPile {
        return self.hundred
    }

    init(hundred: MoneyPile,
           fifty: MoneyPile,
          twenty: MoneyPile,
             ten: MoneyPile) {

        self.hundred = hundred
        self.fifty = fifty
        self.twenty = twenty
        self.ten = ten
    }

    func canWithdraw(amount: Int) -> String {
        return "Can withdraw: \(self.startPile.canWithdraw(amount: amount))"
    }
}

调用及结果:

// Create piles of money and link them together 10 < 20 < 50 < 100.**
let ten = MoneyPile(value: 10, quantity: 6, nextPile: nil)
let twenty = MoneyPile(value: 20, quantity: 2, nextPile: ten)
let fifty = MoneyPile(value: 50, quantity: 2, nextPile: twenty)
let hundred = MoneyPile(value: 100, quantity: 1, nextPile: fifty)

// Build ATM.
var atm = ATM(hundred: hundred, fifty: fifty, twenty: twenty, ten: ten)
atm.canWithdraw(amount: 310) // Cannot because ATM has only 300
atm.canWithdraw(amount: 100) // Can withdraw - 1x100
atm.canWithdraw(amount: 165) // Cannot withdraw because ATM doesn't has bill with value of 5
atm.canWithdraw(amount: 30)  // Can withdraw - 1x20, 2x10

示例分析:

  1. 将所有同一面额的钱抽象为一个对象,同时作为责任链上的接收者,value为面额值,quantity为该面额的数量,nextPile是其链接的下一个接收者。
  2. canWithdraw作为请求的统一接口,canTakeSomeBill判断当前接收者是否可以处理请求,即是否需要取当前面额的钱。(Int类型相除,除数大于被除数时结果为0)。需要取钱时,通过循环在当前接收者进行取钱,当前接收者处理之后,如果仍有待取金额,则传递给下一个接收者处理。
  3. ATM机类将面额由大到小的顺序创建了接收链,canWithdraw作为请求接口,实际则是调用接收者的canWithdraw方法进行具体的请求处理。

小结:如果不使用责任链模式,当传入一个取款请求时,完全使用if...else...或者switch执行,整个代码将耦合起来,并且根据不同面额进行相同的操作会导致代码大量冗余和重复,面额变动时,对代码的维护工作也将变得繁重。而使用责任链模式,请求对象只需要根据需要添加责任链上的接收者,而接收者处理请求的逻辑则不需要关心。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容