iOS開發Swift實戰之模板模式
設計模式(Design pattern)是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。GoF提出了23種設計模式,本系列將使用Swift語言來實現這些設計模式
概述
模板設計模式是最基礎的設計模式之一,在網上被稱作 模板方法模式 ,但實際運用時這種設計模式卻不僅僅局限于方法。因此筆者對于模板設計模式的理解定義如下: > 【模板設計模式】將常見的方法以及對象成員進行封裝,創建了一個實現一組抽象方法以及抽象對象成員作為對象實現使用的模板
壞味道的代碼
在Swift中有個有趣的數據結構—— 元組Tuples ,現在有這么一段代碼。其中傳入的每一個元祖表示某個商品的數據類型:
func calculateTax(product: (String, Double, Int)) -> Double {
return product.1 * 0.17
}
func calculateStockValue(products: [(String, Double, Int)]) -> Double {
return products.reduce(0.0){
$0 + $1.1 * Double($1.2)
}
}
override func viewDidLoad() {
super.viewDidLoad()
let products = [
("Pizazz", 99.8, 10),
("Hamburger", 25.6, 8),
("Beef", 19.9, 30) ]
print("The tax of \(products[0].1) is \(calculateTax(product[0]))")
print("The stock value of all products is \(calculateStockValue(products))")
} 上面的方法通過傳入一個或者多個元組用來計算增值稅(17%)以及商品存貨總額。毫無疑問,對于稍有經驗的開發者來說,都能說出這段代碼有太大的`壞味道`了:兩個方法過度的依賴于傳入的元組結構,這意味著幾乎無法復用這些方法
模板設計模式
在開發語言從面向過程發展到面向對象的過程中,高級語言以及開發框架早已利用各種設計模式進行了封裝,我們在不知不覺中享受著這種封裝帶來的便利卻不自知。上方代碼中的 壞味道 主要因為參數類型以及參數值受到限制,為了避免這種 壞味道 出現,通常使用 模板設計模式 來解決過高的耦合度。
在Swift中,模板設計模式通過使用 class 和 struct 兩種數據類型作為類對象的創建結構模板,用來創建不同內容的具體對象。因此改變之后的代碼如下:
func calculateTax(product: Product) -> Double {
return product.price * 0.17
}
func calculateStockValue(products: [Product]) -> Double {
return products.reduce(0){
return $0 + $1.price * Double($1.stock)
}
}
class Product {
var name: String
var price: Double
var stock: Int
init(name: String, price price: Double, stock stock: Int) {
self.name = name
self.price = price
self.stock = stock
}
}
通過以 class 結構為模板,我們可以創建各種不同屬性的商品。雖然在定義 class 結構的過程中增加了一些額外的工作,但一來這使得我們的代碼更加符合 OOP 的編程思想,二來解除了方法和元組之間的高度耦合。但這樣的代碼仍然存在另一個耦合問題——方法和類之間的耦合。如果有一天,項目需要面對全球市場,但是在不同的國家稅種不同、稅率也不同,這段代碼也就有了另外的 壞味道 。因此我們需要把這兩個方法同樣放到 class 結構中成為方法模板
class Product {
var name: String
var price: Double
var stock: Int
init(name: String, price price: Double, stock stock: Int) {
self.name = name
self.price = price
self.stock = stock
}
private func calculateTax() -> Double {
return price * 0.17
}
private func calculateStockValue() -> Double {
return price * Double(stock)
}
func log() {
print("The tax of \(name) is \(calculateTax())")
print("The stock value of product is \(calculateStockValue())")
}
}
class Product_Japan: Product {
override private calculateTax() -> Double {
return price * 0.05
}
}
將方法抽象封裝到父類中,并在子類中重寫具體實現,這是 模板方法模式 的典型做法
為了計算不同地區的稅率要實現多個這樣的子類的做法帶來的代碼量也是十分可觀的,而且當稅率成了一個可改變的因素時,方法可以改變成為接收稅率進行計算:
func calculateTax(ratio: Double) -> Double {
return price * ratio
}
總結
模式優點
-
將不變的行為抽離封裝起來,去除了重復代碼
-
通過子類重寫父類實現,可以擴展新的行為
模式缺點
-
class 和 struct 都能利用模板模式來解除高耦合,但兩者在傳遞時采用不同的方式,這容易引發錯誤
-
容易造成子類的數量暴增,導致代碼設計更加抽象
來自: http://allluckly.cn/投稿/tuogao51