美文网首页
[IOS架构]面向协议编程POP

[IOS架构]面向协议编程POP

作者: 沈枫_ShenF | 来源:发表于2020-09-21 13:08 被阅读0次

swift中灵活使用协议可以帮助我们编写干净的代码,而且协议还有以下好处。

可测试

public enum Error: Swift.Error {
 case connectivity
 case invalidData
}
protocol Service {
 func fetchData(_ callback: @escaping ([Data]?, Error?) -> ())
}
class DataService: Service {
 func fetchData(_ callback: @escaping ([Data]?, Error?) -> ()) {
  // fetch data
 }
}

现在,怎么去测试这个类呢,当然肯定不会点击去真正的请求URL并等待响应,然后断言结果。相反,我们只需要创建一个模拟类来测试:

class ServiceTest: XCTestCase {
 func test_noData_returnsNoData() {
  let sut = ServiceSpy(data: nil, error: Error.connectivity)
  
  sut.fetchData { (data, error) in
   XCTAssertNil(data)
   XCTAssertNotNil(error)
  }
 }
 func test_withData_returnsData() {
  let sut = ServiceSpy(data: Data(base64Encoded: “test_data”), error: nil)
  sut.fetchData { (data, error) in
   XCTAssertNotNil(data)
   XCTAssertNil(error)
  })
 }
 class ServiceSpy: Service {
  var data: Data?
  var error: Error?
  init(data: Data?, error: Error?) {
   self.data = data
   self.error = error
  }
  func fetchData(_ callback: @escaping ([Data]?, Error?) -> ()) {
   if let data = data {
    callback(data, nil)
   }
   if let error = error {
    callback(nil, error)
   }
  }
 }
}

这样做有利于增加代码的覆盖率,提高可测试性。

可实现多重继承

protocol Talkable {
 func talk()
}
extension Talkable {
 func talk() {
  print(“Person can Talk”)
 }
}
protocol Walkable {
 func walk()
}
extension Walkable {
 func walk() {
  print(“Person can Walk”)
 }
}
class Person: Talkable, Walkable {
}
let person = Person()
person.talk()
person.walk()

依赖注入

依赖注入优点:

  • 单一职责原则
  • 可测试性
  • 避免单例实例的突变
    等等...

依赖注入要求我们传入的参数遵循协议,这样做的好处是:

  • 我们可以在外部注入一个通用类,只要它遵循协议。
  • 也可以注入一个可测试的模拟类,便于测试。
protocol HelloViewModelable {
 func fetchHello()
}
protocol HelloViewControllerable {
 func updateView(hello: String)
}
class HelloViewModel: HelloViewModelable {
 weak var delegate: HelloViewControllerable?
 func fetchHello() {
  delegate?.updateView(hello: “Hello”)
 }
}
class HelloViewController: UIViewController, HelloViewControllerable {
 let viewModel: HelloViewModelable
 @IBOutlet weak var helloLabel: UILabel!
 init(viewModel: HelloViewModelable) {
  self.viewModel = viewModel
  self.viewModel.delegate = self
 }
 override func viewDidLoad() {
  super.viewDidLoad()
  viewModel.fetchHello()
 }
 func updateView(hello: String) {
  DispatchQueue.main.async { [weak self] in
   self?.helloLabel.text = “\(hello)”
  }
 }
}

这里我们在控制器中注入了一个HelloViewModel,实际上我们也可以注入一个HelloViewModel的变体,当然,也可以注入一个可测试的模拟viewModel。

复用

通过协议扩展,我们可以在实现相同功能的多个类中重用一段代码。

protocol Breathable {
 func breathe()
}
extension Breathable {
 func breathe() {
  print(“This creature can breathe.”)
 }
}
struct Fish: Breathable {
}
struct Bird: Breathable {
}
struct Elephant: Breathable {
}
let fish = Fish()
let bird = Bird()
let elephant = Elephant()
fish.breathe()
bird.breathe()
elephant.breathe()

相关文章

网友评论

      本文标题:[IOS架构]面向协议编程POP

      本文链接:https://www.haomeiwen.com/subject/ebfczctx.html