Alex Liang

Swift Protocol Oriented Programming

上一篇介紹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
6
protocol Movable {
func move()
}
protocol FastMovable: Movable {
func move()
}

Standard Library Protocols

Swift語言包含各種protocol,可分為三種類別:”Can Do”, “Is A”, “Can Be”
這三種protocol的命名方式也是Swift的慣例

  1. Can Do: 表示object可以做什麼,例如Standard Library中Equatable表示物件能判斷是否相等
  2. Is A: 表示object是某種形態,例如IntegerType
  3. 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
36
enum 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的可讀性增加,並且更有彈性。

參考來源:
What the 55 Swift Protocols taught me
官方文件