面向协议编程 (Protocol Oriented Programming,以下简称 POP) 是 Apple 在 2015 年 WWDC 上提出的 Swift 的一种编程范式。相比与传统的面向对象编程 (OOP),POP 显得更加灵活。
- 如何将BVC和DVC的公共方法 testMethod抽取出来
class BVC: UIViewController
{
func testMethod() {
print("测试方法")
}
}
class DVC:UITableViewController{
func testMethod() {
print("测试方法")
}
}
一、OOP解决方案
1、用新的类型来提供这个功能
class testTool{
func testMethod() {
print("测试方法")
}
}
class ViewCotroller: UIViewController
{
var testtool:testTool?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.testtool = testTool()
self.testtool?.testMethod()
}
}
class tableViewContoller:UITableViewController{
var testtool:testTool?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.testtool = testTool()
self.testtool?.testMethod()
}
}
- 依赖注入引入额外的依赖关系,可能也是我们不太愿意看到的。
2、UIViewController 上添加 extension
extension UIViewController{
func testMethod() {
print("测试方法")
}
}
let v = ViewCotroller()
v.testMethod()
let t = tableViewContoller()
t.testMethod()
- 看起来这是一个稍微靠谱的做法,但是给任何UIViewController类都添加了testMethod,这种添加代码影响也是不可估计 的,不想看到的。
二、POP解决方案
import UIKit
protocol test{
func testMethod()
}
extension test{
func testMethod(){
print("测试方法")
}
}
class ViewCotroller: UIViewController,test
{
}
class tableViewContoller:UITableViewController,test{
}
let v = ViewCotroller()
let t = tableViewContoller()
v.testMethod()
t.testMethod()
- 通过易个协议扩展,我们只需要简单地声明 ViewController 和 tableViewContoller 遵守 test,就可以直接使用 testMethod 的实现了:
三、POP的应用
使用注意点:
- 1、 优先考虑创建协议,而不是父类(基类)
- 2、优先考虑值类型(struct、enum),而不是引用类型(class)
- 3、巧用协议的扩展功能
- 4、不要为了面向协议而使用协议。
四、优雅的前缀
如果我们设计一个可以计算字符串长度的方法
4.1、直接扩展一个方法
extension String{
func numberCount() -> Int {
return self.count
}
}
print(string.numberCount())
4.2、扩展一个计算属性
extension String{
var mj_numberCount :Int{
return self.count
}
}
print(string.mj_numberCount)
4.3、加一个前缀避免和系统方法冲突
struct Mj {
var string:String
init(_ str:String) {
self.string = str
}
var numberCount :Int{
return self.string.count
}
}
extension String{
var mj:Mj{return Mj(self)}
}
print(string.mj.numberCount)
struct Mj<Base>{
var base:Base
init(_ base:Base) {
self.base = base;
}
}
extension String{
var mj:Mj<Self>{return Mj(self)}
}
extension Int{
var mj:Mj<Self>{return Mj(self)}
}
extension Mj where Base == String{
var numbercount :Int{
return self.base.count
}
}
extension Mj where Base == Int{
var floatcount :Float{
return Float(self.base)
}
}
var string = "测试"
print(string.mj.numbercount)
var a = 10
print(a.mj.floatcount)
4.4、使用协议优雅的添加一个前缀
struct Mj<Base>{
var base:Base
init(_ base:Base) {
self.base = base;
}
}
protocol MJCompatable{}
extension MJCompatable{
var mj:Mj<Self>{
get {Mj(self)}
set{}
}
}
extension String:MJCompatable{}
extension Mj where Base == String{
var numbercount :Int{
return self.base.count
}
}
extension Int:MJCompatable{}
extension Mj where Base == Int{
var floatcount :Float{
return Float(self.base)
}
}
var string = "测试"
print(string.mj.numbercount)
var a = 10
print(a.mj.floatcount)
五、使用协议实现类型判断
判断一个是否为一个数组
func isArray(_ value: Any) -> Bool {
value is [Any]
}
print(isArray(NSArray()))
print(isArray([1,"2"]))
print(isArray("123444"))
import Foundation
protocol Arraytype {}
extension Array: Arraytype{}
extension NSArray: Arraytype{}
func isArrayType(_ type: Any.Type) -> Bool {
type is Arraytype.Type
}
print(isArrayType([Int].self))
print(isArrayType([Any].self))
print(isArrayType(NSArray.self))
isArrayType(NSMutableArray.self)
网友评论