在swift中对类和struct进行扩展或使用协议扩展(本质是mixin),是非常简单且实用的语法。但是语法糖太好用了就可能乱用并产生混乱(比如,团队中对时间处理做了很多的扩展)。这两天看ReactiveSwift源码学到了一种比较好的写法来解决这个问题。先看demo:
// 我们有两个Model类
class MyModel {
var tableName: String {
return "tbl_model_1"
}
var itemA: Int?
var itemB: String?
}
class MyModel2 {
var itemA: Bool?
var itemB: [Int]?
}
// 需要增加Log功能的协议
protocol Loggable { }
extension Loggable {
// 利用Self约束,限定使用log功能的扩展包装类
var logger: Logger<Self> {
return Logger(self)
}
}
// 我们将所有和log相关的扩展统一用Logger包装
struct Logger<Base: Loggable> {
var base: Base
init(_ base: Base) {
self.base = base
}
}
// 针对MyModel进行log功能的定制扩展
extension MyModel: Loggable { }
extension Logger where Base: MyModel {
func dumpForDb() {
print("tableName:\(base.tableName), itemA:\(base.itemA), itemB:\(base.itemB)")
}
}
// 针对MyModel2进行log功能的定制扩展
extension MyModel2: Loggable { }
extension Logger where Base: MyModel2 {
func dumpSelf() {
dump(base)
}
}
// 具体使用
let my1 = MyModel()
let my2 = MyModel2()
my1.logger.dumpFOrDb()
my2.logger.dumpSelf()
这里面的基本思路就是利用一个struct去包装要进行扩展的具体类或struct,所以my1.logger等同于Logger(my1)。有了这个小技巧我们的代码就可以写的更加清晰了,比如有:
my1.mapping.toJSON() // Model映射扩展
my1.db.save() // 数据库操作扩展
my1.net.request() // 网络操作扩展
是不是很好用!
网友评论