本文是對(duì)Design Patterns implemented in Swift 3.0的解讀和翻譯熊镣,通過這些案例對(duì)Swift中的設(shè)計(jì)模式進(jìn)行總結(jié)和加深理解钉嘹。
本文示例代碼都是在Xcode的Playground
上運(yùn)行的。
什么是設(shè)計(jì)模式
設(shè)計(jì)模式(Design Patterns)是面向?qū)ο蟪绦蜷_發(fā)過程中總結(jié)出來的代碼設(shè)計(jì)方式偶器。設(shè)計(jì)模式為程序開發(fā)所遇到的各種情景提供了最佳解決方案抬虽,合理地運(yùn)用設(shè)計(jì)模式抹沪,可以提高代碼的復(fù)用性,降低代碼的耦合度吻氧,提升程序的靈活度等等溺忧,從而有效的提高開發(fā)效率。
設(shè)計(jì)模式按功能大概可分為三類:
- 行為型模式(Behavioral):主要關(guān)注對(duì)象之間的通信
- 創(chuàng)建型模式(Creational):主要關(guān)注對(duì)象的創(chuàng)建盯孙,根據(jù)實(shí)際情景鲁森,通過其方法創(chuàng)建對(duì)象,而非直接實(shí)例化對(duì)象振惰,使創(chuàng)建對(duì)象更加靈活歌溉。
- 結(jié)構(gòu)型模式(Structural):關(guān)注類和對(duì)象的組合。通過繼承骑晶、協(xié)議等方式增加對(duì)象的功能痛垛。
設(shè)計(jì)模式的淺析和實(shí)踐
行為型模式
責(zé)任鏈模式(Chain Of Responsibility)
責(zé)任鏈模式用于處理不同的請(qǐng)求(request),每個(gè)請(qǐng)求會(huì)被不同的程序處理桶蛔。
原理:為請(qǐng)求提供統(tǒng)一的方法匙头,請(qǐng)求的接收者則根據(jù)不同的請(qǐng)求進(jìn)行不同處理。多個(gè)可以接收請(qǐng)求的對(duì)象組成一條鏈仔雷,符合條件的接收者會(huì)對(duì)請(qǐng)求處理蹂析,不符合條件的接收者將請(qǐng)求傳遞給鏈的下一個(gè)接收者,直到鏈的最后碟婆。
目的:將請(qǐng)求者與接收者解耦电抚,降低代碼耦合度
示例說明:
ATM機(jī)中存在面額為100、50脑融、20喻频、10元的鈔票若干,當(dāng)向ATM查詢是否可以提取任意金額現(xiàn)金時(shí)肘迎,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))"
}
}
調(diào)用及結(jié)果:
// 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
示例分析:
- 將所有同一面額的錢抽象為一個(gè)對(duì)象疤苹,同時(shí)作為責(zé)任鏈上的接收者补憾,
value
為面額值,quantity
為該面額的數(shù)量堆生,nextPile
是其鏈接的下一個(gè)接收者匣沼。 -
canWithdraw
作為請(qǐng)求的統(tǒng)一接口狰挡,canTakeSomeBill
判斷當(dāng)前接收者是否可以處理請(qǐng)求,即是否需要取當(dāng)前面額的錢。(Int
類型相除加叁,除數(shù)大于被除數(shù)時(shí)結(jié)果為0)倦沧。需要取錢時(shí),通過循環(huán)在當(dāng)前接收者進(jìn)行取錢它匕,當(dāng)前接收者處理之后展融,如果仍有待取金額,則傳遞給下一個(gè)接收者處理豫柬。 - ATM機(jī)類將面額由大到小的順序創(chuàng)建了接收鏈告希,
canWithdraw
作為請(qǐng)求接口,實(shí)際則是調(diào)用接收者的canWithdraw
方法進(jìn)行具體的請(qǐng)求處理烧给。
小結(jié):如果不使用責(zé)任鏈模式燕偶,當(dāng)傳入一個(gè)取款請(qǐng)求時(shí),完全使用if...else...
或者switch
執(zhí)行础嫡,整個(gè)代碼將耦合起來指么,并且根據(jù)不同面額進(jìn)行相同的操作會(huì)導(dǎo)致代碼大量冗余和重復(fù),面額變動(dòng)時(shí)驰吓,對(duì)代碼的維護(hù)工作也將變得繁重涧尿。而使用責(zé)任鏈模式,請(qǐng)求對(duì)象只需要根據(jù)需要添加責(zé)任鏈上的接收者檬贰,而接收者處理請(qǐng)求的邏輯則不需要關(guān)心姑廉。