在上一篇介紹Swift Protocol基本的用法和優點。
這篇接著討論Swift使用protocol帶來的設計觀念:Protocol Oriented Programming
Composition
在物件導向設計中,繼承(inheritance)是常被誤用的觀念。
當二個”看起來”類似的類別套入繼承的關係後,有些操作便不適合
例如:圓形和橢圓形適合使用繼承的關係嗎? 前者有半徑;後者有長軸和短軸
如果將橢圓形繼承圓形,則初始化時,半徑為無意義的值
所以在重構時,很重要的一點是分㦚二個類別是”Is A”或”Has A”的關係
如同前例,橢圓形並”不是”一種圓形;相反的,跑車”是”車子的一種
於是討論這類問題時,組合(composition)是一個更適合的pattern
Protocol Inheritance
由於Swift的class只能繼承單一class,但class能擁有多個protocol
所以在設計class時,我們傾向將各特性分為各種protocol
而protocol能繼承另一個protocol,可以組合各種小功能的protocol完成有彈性的設計1
2
3
4
5
6protocol Movable {
func move()
}
protocol FastMovable: Movable {
func move()
}
Standard Library Protocols
Swift語言包含各種protocol,可分為三種類別:”Can Do”, “Is A”, “Can Be”
這三種protocol的命名方式也是Swift的慣例
- Can Do: 表示object可以做什麼,例如Standard Library中Equatable表示物件能判斷是否相等
- Is A: 表示object是某種形態,例如IntegerType
- Can Be: 表示object可以轉化成某種形態,例如ArrayLiteralConvertible表示物件能轉成array形態
Protocol Oriented Programming
假如有個class為Car,我們可以利用protocol組合該類別的基本行為1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36enum Direction {
case Up, Down, Left, Right
}
struct Position {
let x: Int
let y: Int
}
protocol Movable {
func move(direction: Direction, distance: Int)
}
protocol VehicleType {
var hoursePower: Int { get set }
var price: Double { get set }
init(position: Position)
}
class Car: VehicleType, Movable {
var hoursePower: Int = 200
var price: Double = 4000.25
required init(position: Position) {
self.position = position
}
func move(direction: Direction, distance: Int) {
switch direction {
case .Up: position.y += distance
case .Down: position.y -= distance
case .Left: position.x -= distance
case .Right: position.x += distance
}
}
使用protocol的組合可以讓class的可讀性增加,並且更有彈性。