本文是对Design Patterns implemented in Swift 3.0的解读和翻译,通过这些案例对Swift中的设计模式进行总结和加深理解。
本文示例代码都是在Xcode的Playground
上运行的。
什么是设计模式
设计模式(Design Patterns)是面向对象程序开发过程中总结出来的代码设计方式。设计模式为程序开发所遇到的各种情景提供了最佳解决方案,合理地运用设计模式,可以提高代码的复用性,降低代码的耦合度,提升程序的灵活度等等,从而有效的提高开发效率。
设计模式按功能大概可分为三类:
- 行为型模式(Behavioral):主要关注对象之间的通信
- 创建型模式(Creational):主要关注对象的创建,根据实际情景,通过其方法创建对象,而非直接实例化对象,使创建对象更加灵活。
- 结构型模式(Structural):关注类和对象的组合。通过继承、协议等方式增加对象的功能。
设计模式的浅析和实践
行为型模式
责任链模式(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
示例分析:
- 将所有同一面额的钱抽象为一个对象,同时作为责任链上的接收者,
value
为面额值,quantity
为该面额的数量,nextPile
是其链接的下一个接收者。 -
canWithdraw
作为请求的统一接口,canTakeSomeBill
判断当前接收者是否可以处理请求,即是否需要取当前面额的钱。(Int
类型相除,除数大于被除数时结果为0)。需要取钱时,通过循环在当前接收者进行取钱,当前接收者处理之后,如果仍有待取金额,则传递给下一个接收者处理。 - ATM机类将面额由大到小的顺序创建了接收链,
canWithdraw
作为请求接口,实际则是调用接收者的canWithdraw
方法进行具体的请求处理。
小结:如果不使用责任链模式,当传入一个取款请求时,完全使用if...else...
或者switch
执行,整个代码将耦合起来,并且根据不同面额进行相同的操作会导致代码大量冗余和重复,面额变动时,对代码的维护工作也将变得繁重。而使用责任链模式,请求对象只需要根据需要添加责任链上的接收者,而接收者处理请求的逻辑则不需要关心。