Swift & runtimeHistorical technical note
Swift in practice: the template pattern
Uses product data and calculations to examine code that depends on a tuple's structure. Types and protocols then organise reusable processing, showing how abstraction can reduce coupling between parameter formats and business methods.
Originally credited to Sindri; edited and archived by Bison.
Source listed in the originalOn this page

Design patterns are classified, widely known, repeatedly used solutions distilled from code-design experience. The GoF proposed 23 patterns; this series implements them in Swift.
Editor: Bison
Contributor: Sindri’s Notes
Overview
The template design pattern is one of the most basic patterns. Online, it is commonly called the 模板方法模式, but in practice its application is not limited to methods. My own definition is therefore:
[Template design pattern] Encapsulate common methods and object members in a template providing abstract methods and members for concrete implementations.
Code smells
Swift has an interesting data structure, 元组Tuples. In the following code, each tuple passed in represents the data for a product:
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%)以及商品存货总额。毫无疑问,对于稍有经验的开发者来说,都能说出这段代码有太大的`坏味道`了:两个方法过度的依赖于传入的元组结构,这意味着几乎无法复用这些方法

Template design pattern
As languages evolved from procedural to object-oriented programming, high-level languages and frameworks encapsulated many design patterns. We often benefit from this without noticing. The 坏味道 in the code above comes mainly from restrictions on parameter types and values. To avoid this 坏味道, a common approach is to use 模板设计模式 to reduce excessive coupling.

In Swift, the template design pattern uses class and struct as structural templates for creating concrete objects with different contents. The revised code is:
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
}
}
Using a class structure as the template, we can create products with different properties. Defining the class adds some work, but makes the code more consistent with OOP and removes the tight coupling between methods and tuples. Another coupling remains, however, between methods and classes. If the project later serves global markets with different tax types and rates, the code acquires another 坏味道. We therefore also need to move these two methods into the class structure as method templates.
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
}
}
Abstracting methods into a superclass and overriding their concrete implementations in subclasses is a typical use of 模板方法模式.

Implementing multiple subclasses for regional tax rates creates substantial code. When the rate becomes a variable, change the method to accept it:
func calculateTax(ratio: Double) -> Double {
return price * ratio
}
Summary
Pattern advantages
-
Extract and encapsulate invariant behaviour, removing duplicated code.
-
Subclasses override superclass implementations to add new behaviour.
Pattern disadvantages
-
Both
classandstructcan use the template pattern to reduce coupling, but their different passing semantics can cause errors. -
can cause an explosion of subclasses and make the design more abstract.
Recommended reading: Adding a launch advertisement to an iOS app