ios 从 OOP 到 POP 面向对象到面向协议

2,020 阅读3分钟

区分简单理解

  • 面向对象: 一个人 名字/年龄/跑/吃
  • 面向协议: 是一个人,可以有很多能力(协议)

面向对象

  • 传统的面向对象思维方式:
    • 有一只狗,有自己的名字, 可以跑
    • 有一只猫,有自己的名字, 可以跑
    • 有一个人,有自己的名字, 可以跑
    • 抽象出一个动物类, 之后, 将跑的行为放入动物类中
    • 如果需要一个吃的行为, 也可以抽象在动物类中
  • Animal 作为基类,构建跑和吃的行为方法
class Animal: NSObject {
    func running() {
        print("跑")
    }
    
    func eating() {
        print("吃")
    }
}
  • Dog 作为子类,调用父类的方法
    • Dog 作为子类 继承自父类
    • 子类中 子类重写父类的方法,父类指针指向子类。 多态
    • 同理 Cat、Person 也是这样的
  • 多态的三个条件
    • 继承:各种子类继承自父类
    • 重写:子类重写了父类的方法 eating()、running()
    • 指向:父类指针指向子类
class Dog : Animal{
    override func eating(){
        super.eating()
        print("狗在吃")
    }
    override func running(){
        super.running()
    }
}
  • 面向对象开发弊端
    • 如果有一个机器人(一辆车), 也有跑的行为, 这个时候如何抽象呢, 显然该抽象方式并不是特别合理
    • 显然car、robot不能继承自Animal因为他们不是animal 只能在抽取一个基类或者自己写自己的

class Car: NSObject {
    
    func running() {
        
    }
}

class Robot: NSObject {
    func running() {
        
    }
}
  • 真实开发场景中
    • 对UIViewController/UITableViewController/UICollectionViewController抽象相同的方法
    • 所以你可能需要做 BaseViewController/BaseTableViewController/BaseCollectionViewController 三个控制器的基类(还是很复杂)
    • 如果你要去别的项目复制部分功能时,有些要复制,有些又不要复制,抽取就比较麻烦了
  • 面向对象开发核心是: 封装-继承-(多态)

面向协议示例

  • Swift 标准库中有 50 多个复杂不一的协议,几乎所有的实际类型都是满足若干协议的
  • 面向协议开发核心是: 模块化(组件化)
  • 面向协议开发应用:
    • 粒子动画效果实现, 抽取在单独的协议中, 如果有控制器需要, 实现我的协议即可
    • 很多UIView会通过xib进行描述, 而我们经常需要从一个xib中加载UIView, 抽取单独的协议, 需要从xib中加载类, 只需要遵守协议即可

简单示例

  • 当UIViewController/UITableViewController/UICollectionViewController 都需要一个Test方法时
  • 写一个Testable.swift
  • 给自定义的协议中添加extension,在extension中对可选方法进行默认实现,这样遵守协议的对象就可以不用实现可选方法.
  • 代码示例:
import Foundation

protocol Testable {
    //这里只能写声明 并且声明中不能做方法的实现否则报错
//    func demo() // 必须
	func test() // 可选
}
//要实现协议的实现必须做个扩展 extension 相当于OC的extinction 文件拓展一样的 swift就很方便了
extension Testable {
    func test() {
        print("对代码进行简单测试")
    }
}

class OneViewController: UIViewController, Testable
class TwoViewController: UITableViewController, Testable
class ThreeViewController: UICollectionViewController, Testable
  • 三个类各自遵守协议 在合适的位置写入方法就可以了

重新回到eating和running

  • 子类遵守协议实现方法就可以了
import Foundation


protocol Runable {
}


extension Runable {
    func running() {
        print("正在跑ing")
    }
}

import Foundation


protocol Eatable {
}

extension Eatable {
    func eating(){
        print("正在吃东西ing")
    }
}


class Cat: NSObject, Runable {
}
class Person: NSObject, Runable {

}

面向协议的条件 只有当前的类是UIViewController 才能遵守协议

protocol Emitterable {
    
}
extension Emitterable where Self : UIViewController

网络请求(使用面向协议方式进行开发)

protocol Requestable {
    var method : HttpMethod { get }
    var host : String { get }
    var path : String { get }
    var parameters : [String : Any] { get }

    associatedtype ResultType : Decodable
}

extension Requestable {
    func request(completion : @escaping (ResultType?) -> Void) {
        // 1.创建URL
        let url = URL(string: host + path)!

        // 2.创建request对象
        let request = URLRequest(url: url)

        // 3.通过URLSession发送请求
        let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, _, error) in
            completion(ResultType.parse(data!))
        })

        // 4.发起请求
        task.resume()
    }
}

protocol Decodable {
    static func parse(_ data : Data) -> Self?
}