在开发的过程中,很多时候我们会对系统的或者三方库提供的类结构体枚举进行扩展。不同的开发者习惯不一样,然后也不知道自己所需要的功能是否已经被扩展了。在扩展功能给函数取名字的时候就有可能会出现函数已经存在了,或者是项目中导入的多个库里面都给一个类型扩展了同一个名字的函数。 在`Objective-C`中,给系统的类或者三方库的类进行扩展功能,函数名用`xxx_`做前缀,避免冲突。 在`Swift`中,有更优雅的方式来避免冲突的发生了。那就是利用协议和其默认实现做到类似于`C++`的命名空间效果。 首先定义`BaseWrapper`结构体包装器,该结构体包装器用于包装需要操作的对象。结构体是值类型,函数内使用它的时候分配的内存空间在栈里,用完后就会释放;不会产生太多的内存开销。这里使用泛型编程,不同的类型包装里面的类型也不一样。 ```swift public struct BaseWrapper { public var base: BaseType public init(_ value: BaseType) { self.base = value } } ``` 用于包装对象的`WrapperSpace`和`BaseWrapper`就处理好了,接下来就是定义用于实现名称空间的协议了: ```swift public protocol NameSpace { associatedtype BaseType var dvt: BaseType { get } static var dvt: BaseType.Type { get } } ``` `NameSpace`协议提供了关联类、实例对象、类对象。关联类用来说明该协议是由哪个类来实现的,实例对象用来调用扩展的实例方法,类对象用来调用扩展的类方法。 然后利用`Swift`的协议默认实现来完成对象的包装: ```swift public extension NameSpace { var dvt: BaseWrapper { get { BaseWrapper(self) } } static var dvt: BaseWrapper.Type { get { BaseWrapper.self } } } ``` 接下来就是如何使用了: 首先,将需要扩展的类型实现NameSpace协议: ```swift extension String: NameSpace { } ``` `Swift`的协议默认实现功能节省了开发者部分重复工作,只需要实现`NameSpace`协议就有`dvt`包装器了。 然后就需要开始扩展功能了,扩展功能实现可以扩展包装器`BaseWrapper`: ```swift public extension BaseWrapper where BaseType == String { /// 正则校验 func regularValidate(_ regular: String) -> Bool { let predicate = NSPredicate(format: "SELF MATCHES %@", regular) return predicate.evaluate(with: self.base) } } ``` 上面的代码给`String`添加了一个快速正则校验的API,使用方法如下: ```swift let string = "18112341234" if string.dvt.regularValidate("^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$") { print("是手机号码") } else { print("不是手机号码") } ``` > 校验手机号码的正则表达式是随便找的,可能有新的号段手机号码不在这个正则范围内
没有评论