定义

  • 面向协议编程(Protocol Oriented Programming, 简称POP)
    • 是Swift的一种编程范式,Apple于2015年WWDC提出
    • 在Swift标准库中,能见到大量POP的影子
  • 同时,Swift也是一门面向对象的编程语言(Object Oriented Programming, 简称OOP)
  • 在Swift开发中,OOP和POP是相辅相成的,任何一方并不能取代另一方
  • POP能弥补OOP一些设计上的不足

OOP

  • OOP的三大特性:封装,继承,多态
  • 继承的经典使用场合:
  • 当多个类(比如A, B, C类)具有很多共性时,可以将这些共性抽取到一个父类中(比如D类),最后A, B, C类继承D类

OOP的缺点

  • 比如,如何将下面BVC, DVC的公共方法run抽取出来?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class BVC: UIViewController {
    func run() {
    print("run")
    }
    }

    class DVC: UITableViewController {
    func run() {
    print("run")
    }
    }
  • 基于OOP想到的一些解决方案:
    1. 将run方法放到另一个对象A中,然后BVC, DVC拥有对象A的属性,此时,多了一些额外的依赖关系
    2. 将run方法增加到UIViewController分类中,不过UIViewController会越来越臃肿,而且会影响它的其他所有子类
    3. 将run方法抽取到新的父类,采用多继承,会增加程序设计复杂度,产生菱形继承等问题,需要开发者额外解决

解决方案:通过协议的方式

1
2
3
4
5
6
7
8
9
10
11
protocol Runnable {
func run()
}
extension Runnable {
func run() {
print("run")
}
}

class BVC: UIViewController, Runnable {}
class DVC: UITableViewController, Runnable {}

POP的注意点

  • 优先考虑创建协议,而不是父类(基类)
  • 优先考虑值类型(struct, enum),而不是引用类型(class)
  • 巧用协议的扩展功能
  • 不要为了面向协议而使用协议

利用协议实现前辍效果

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
struct HX<Base> {
let base: Base
init(_ base: Base) {
self.base = base
}
}

protocol HXCompatible {}
extension HXCompatible {
static var hx: HX<Self>.Type {
get { HX<Self>.self }
set {}
}
var hx: HX<Self> {
get { HX(self) }
set {}
}
}

//对系统库进行扩展
extension String: HXCompatible {}
extension HX where Base == String {
func numberCount() -> Int {
var count = 0
for c in base where ("0"..."9").contains(c) {
count += 1
}
return count
}
}

//使用
var string = "123fdsf434"
print(string.hx.numberCount())

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person {}
class Student: Person {}

extension Person: HXCompatible {}
extension HX where Base: Person {
func run() {}
static func test() {}
}

Person.hx.test()
Student.hx.test()

let p = Person()
p.hx.run()

let s = Student()
s.hx.run()

示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//对Sting, NSString进行扩展
extension String: HXCompatible {}
extension NSString: HXCompatible {}
extension HX where Base: ExpressibleByStringLiteral {
func numberCount() -> Int {
let string = base as! String
var count = 0
for c in string where ("0"..."9").contains(c) {
count += 1
}
return count
}
}

var s1: String = "123fdsf434"
var s2: NSString = "123fdsf434"
var s3: NSMutableString = "123fdsf434"
print(s1.hx.numberCount())
print(s2.hx.numberCount())
print(s3.hx.numberCount())

利用协议实现类型判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//普通判断数组方法
func isArray(_ value: Any) -> Bool { value is [Any] }
isArray( [1, 2] )
isArray( ["1", 2] )
isArray( NSArray() )
isArray( NSMutableArray() )

//对Array, NSArray进行扩展方法
protocol ArrayType {}
extension Array: ArrayType {}
extension NSArray: ArrayType {}
func isArrayType(_ type: Any.Type) -> Bool { type is ArrayType.Type }

isArrayType([Int].self)
isArrayType([Any].self)
isArrayType(NSArray.self)
isArrayType(NSMutableArray.self)

参考

  • 李明杰老师课件