A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© faceseagod 中级黑马   /  2015-10-13 23:35  /  1043 人查看  /  2 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

Cocos开发者平台
Cocos引擎中文官网
Cocos商店
登录注册


iOS 8 Swift App Store Apple Watch Metal Cocos引擎 手游
iOS开发App Store研究应用评测产品设计Cocos引擎WebAppSwift游戏开发苹果相关营销推广业界动态程序人生论坛代码专题活动招聘
首页 >Swift
不要用子类!Swift的核心是面向协议

2015-08-03 16:19 编辑: suiling 分类:Swift 来源:ray16897188的简书  9 8503
协议Swift子类OOP
招聘信息:
iOS开发工程师
Cocos2d-X 前端主程
iOS高级开发工程师(急招)
iOS资深开发工程师
iOS开发工程师
前端工程师
iOS工程师&技术经理&总监
iOS开发工程师
cocos2dx开发工程师----在线等,挺急的~
求iOS攻城狮一枚

woman-737437_640.jpg

作者:ray1689718 授权本站转载。

本篇文章翻译自:IF YOU'RE SUBCLASSING, YOU'RE DOING IT WRONG.
原作者:Hector Matos
原发表日期:2015-07-13
Swift的核心

我们可以通过等式的传递性来理解swift:

Swift的核心是面向协议的编程。
面向协议的编程的核心是抽象(abstraction)和简化(simplicity)。
所以swift的核心就是抽象和简化。
你可能对我的标题感到诧异。我并不是说子类没有价值,尤其在使用单一继承(single inheritance)的情况下,类和子类当然是强有力的工具。然而我想说的是,iOS日常开发的问题是对类和继承的过度使用。作为面向对象的编程者(object-oriented programmer,后面统一替换为OOP编程者;object-oriented programming后面统一简写为OOP)我们总是会自然的倾向于使用引用类型和类去解决问题,但是我个人还是认为应该反过来,倾向于用值类型代替引用类型。我们还是要去写模块化的,可伸缩的并且可重用的代码,这一点不会变。swift中强大的值类型就可以帮我们实现此目的,且不需要对引用类型有过强的依赖。我认为不仅面向协议的编程(protocol oriented programming,后统一替换为POP)可以帮我们实现这点,另外2种编程类型也可以,且都具有抽象和简化的核心思想,这两种分别是:面向值的编程(value-oriented programming,后面统一替换成VOP)和函数式编程(functional programming)。

先说清楚,我绝不是这些种编程类型(POP,VOP和函数式编程)的专家。和你一样,从MMM时代(manual memory management - 手动内存管理)开始我就是一个OOP编程者。通过自学,从开始我就很重视值抽象(value abstraction)和简化的思想。我都没有意识到自己是一个倾向于函数式编程(functional programming)的OOP编程者,而且很多时候用的都是VOP和POP的思路。这可能是我为什么在第一天就兴高采烈的加入了swift的浪潮之中的原因。在WWDC的一整周里,swift的核心理念与我认为的该怎样去编程是如此之契合,这个感受一直充斥在我脑海中。通过这篇文章,我希望能帮助你(OOP的编程者)打开思路,去考虑该如何用更加Non-OOP(非OOP)的方式去解决问题。

OOP的问题(和我不得不去学它的原因)

我会是第一个跳出来说的:不用OOP的话做出iOS应用很难。Cocoa的核心就是OOP。没有OOP的话你根本写不出来一个iOS应用。有时候我会幻想这不是真的。如果你有不同观点,赶快证明我是错的吧。我真的需要这样,求你了,证明我是错的吧!

不管怎么样,你总会遇到必须用对象、用引用类型解决问题的时候,然后由于Cocoa的规定而被迫使用类(classes)。这种情况下你碰到的问题都是我们大家熟知并热爱的:

传递class的实例这个做法好像总是有种不可思议的能力:你想用一个实例的时候,让这个实例的状态(state)和你所期望的不一样。(这是由于可变状态(mutable state)导致,你这个对象的另一个享有者在它觉得合理的时候能够改变此对象的属性。)
如果不用多继承的话,从一个很棒的class派生出子类从而获得它的扩展功能妨碍了你使用另外一些很棒的class的更多更能,而且还增加了复杂性。(举例来说,试着去把2个UITextField的子类结合起来,生成一个拥有这2者特性的超级UITextField吧。)
上面一条的另外一个问题是会引出意外行为(unexpected behavior)。如果你遇见了类似上面一条所描述的情况,你就陷入到了一个依赖问题中:你连接了2个superclass各自的特性,对于其中一个superclass的一处改动可能会给另外一个superclass带来不良影响。这就是被周知的class之间紧耦合(tight coupling)所带来的问题。
单元测试中的mocking。有些classes在系统中的环境状态下耦合过于紧密,想完全测试这些classes就需要你创建每个class的假表象。我都不用告诉你本质上你并没有真正的测试了这个class,你不过是在假装测试它。这里就不提很多Mocking的库是用运行时的小把戏来造一个假的class了。
并发(Concurrency)问题。这和上面提到的可变状态是伴随出现的。你从多个线程中同时改变一个引用就会引起这个问题,在运行时使对象之间的同步发生异常,这点也真的不用和你说了。
很容易导致出现像上帝类(God classes - 承担着很多subclasses需要的重要高层级代码的所有责任),Blobs(有过多职权的classes),Lava Flow(因为含有太多的非法代码导致任何人都不敢碰的classes)等等这些种反面模式(anti patterns)。
blob.png

POP 面向协议的编程

陷入OOP的反面模式特别容易。多半时间我们(包括我)就是太懒而不愿意去点File>New File。结果是在现有class的基础上添加一个函数是如此轻松,我们就不愿意从零开始建一个新的class了。如果你一直这么干,而且一直非常懒的从一个"很重要"的class派生subclass的话,你就把上帝类/死星类给弄出来了。实际上我之前就这么干过:我给一个app里的每个view Controller都加了能呈现一个指向navigationController的navigationBar的error view的功能。唉,我可真蠢。直到要改动那个Error上帝类行为的时候,我不得不把整个app都改一遍。这不是聪明的做法,你真应该看看那些bug。

2 个回复

倒序浏览
OOP很重要啊!
回复 使用道具 举报

swift更注重面向协议吧
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马