设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

充满争议的Swift协议:该如何正确使用?

2015-8-26 21:58| 发布者: joejoe0332| 查看: 736| 评论: 0|原作者: CSDN|来自: CSDN

摘要: 最近Swift的热点都围绕在协议上,他们觉得任何东西都应该是协议。理论上这挺好,但是事实上,这种观点会产生一些副作用。我在代码中使用协议时,总是牢记下面两条规则:…… ...

本文出自:owensd.io,译文出自:SwiftGG

最近Swift的热点都围绕在协议上,他们觉得任何东西都应该是协议。理论上这挺好,但是事实上,这种观点会产生一些副作用。

我在代码中使用协议时,总是牢记下面两条规则:

1. 不要把协议当成类型


我看到的(和我一开始写的)许多方法都是在继承关系里把协议当成一个基类。我不认为这是协议的正确用法,这种设计模式仍然停留在“面向对象”的思维方式上。

换句话说,假如你的协议只在继承关系里有意义,那就应该扪心自问是否真的有必要使用协议。我不赞同这种说法:“我的类型是结构体,所以我需要用协议来代替。”如果真的需要这样,那就重构它,把它变得更通用。

进一步的验证可见:http://swiftdoc.org/swift-2/。需要关注所有那些协议(不以 _ 开头的协议)吗?所有的协议都能适用不同的类型,不管是不是类型继承。

2. 不要把协议泛型化,除非你必须这么做!


这并不是一个小问题,一旦你把协议泛型化,就无法再使用包含不同协议实例的类型集合。我认为这是严重的设计缺陷。比如说,无论在哪里使用协议,协议中所有不受Self限制的功能都应该保证调用安全。

这条规则同样适用于遵守泛型协议的协议,比如Equatable,泛型会传染。

下面这行代码就是典型的例子:

  1. protocol Foo : Equatable {}  

来个实际点的例子吧:

我们想要对HTTP response建模,并且想要支持两种不同的response类型:String和JSON。

你可能会这样写:

  1. class HTTPResponse<ResponseType> {  
  2.     var response: ResponseType  
  3.     init(response: ResponseType) { self.response = response }  
  4. }  

我认为这样写不好。一旦这样写,我们就人为地限制了使用这个类型的能力;比如,这不能在复杂情况下的集合里使用。现在,为什么我想要在集合里使用不同的ResponseType?假设,我想要构建一个 response/request的测试工具。返回response的集合里需要有我支持的类型:String和JSON。

使用AnyObject是个不错的做法。虽然可行,但是真的很操蛋。

另一种方法是使用协议。然而,除了构建ResponseType协议之外,让我们想想真正想要什么。我真正关心的是,HTTPResponse接收到的ResponseType都能表示成String。

揣着这样的想法,我写出这样的代码:

  1. protocol StringRepresentable {  
  2.     var stringRepresentation: String { get }  
  3. }  
  4. class HTTPResponse {  
  5.     var response: StringRepresentable  
  6.     init(response: StringRepresentable) { self.response = response }  
  7. }  

对我而言,这为API使用者提供了极大的方便,也维持了类型的明确性。当然,这样做是有弊端的。假如你真的需要为response使用特定的类型,那么就需要进行类型转换。

  1. class JSONResponse : StringRepresentable {  
  2.     var stringRepresentation: String = "{}"  
  3. }  
  4. let http = HTTPResponse(response: JSONResponse())  
  5. let json = http.response as? JSONResponse  
这个方法明显更好。调用者知道可能的返回类型或返回值。这明显与遍历整个集合取出返回值是不同的,因为,代码的使用者可能使用的是其他的返回类型,比如 XMLResponse ,而我们的代码不可能知道这个。

最好是这样写:

  1. class HTTPResponse<ResponseType : StringRepresentable> {  
  2.     var response: ResponseType  
  3. }  
  4. <span style="font-family: Helvetica, ​Tahoma, ​Arial, ​sans-serif; font-size: 14px; white-space: normal; background-color: initial;">let responses = [json, string] &nbsp;//responses变量是以HTTPResponse为元素的数组,元素中的ResponseType是未指定的。</span>  

如果要用集合,你还是需要强制转换response的类型,不过现在你可以直接用JSON实例来验证类型。

反正我是每次都用[HTTPResponse]类型的集合,而不是[AnyObject]。


预告:2015中国移动开发者大会(MDCC 2015)将于10月15-16日在北京新云南皇冠假日酒店召开。大会特设五大技术专场:平台与技术iOS、平台与技术Android、产品与设计、游戏开发、企业移动化。此外,大会更是首次举办国内极具权威影响力的IoT技术峰会,特设硬件开发技术与虚拟现实两大专场。大会将聚集国内最具实力的产品技术团队,与开发者一道进行最前沿的探讨与交流。


酷毙

雷人

鲜花

鸡蛋

漂亮
  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部