6

编程新手如何理解“面向对象”

 3 years ago
source link: https://zhuanlan.zhihu.com/p/54811357
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

编程新手如何理解“面向对象”

QQ群:1017375061(17bang.ren)再见

先说一点,其实我是不建议新手去“深入”理解面向对象的。所谓“深入”,大概就以“设计模式”为界吧。通常情况下,两年工作经验以下的新人,去研究“设计模式”要么是半途而废(这算是好的),要么就是把自己搞废了(走火入魔)。
这些年,谈“设计模式”的人确实是越来越少了,而且前两天我看到一个问题:面向对象(OOP)是编程语言发展中的弯路吗?为什么?
这个有点狠,呵呵。“弯路”倒谈不上,只能说现在“面向对象”已经被拉下神坛,回归常态:不再是“万物皆对象”的狂热,而应该是在适合面向对象的地方面向对象
不知道大家是否同意:设计模式本质上是对传统面向对象“弊端”的一种修补?这个说得深了一点,新手随便看看就行。
说正事,编程新手应该如何理解“面向对象”?
首先,面向对象仍然是目前最主流、最有效地处理复杂业务逻辑的手段。大家不要矫枉过正,听有些家伙叫嚣“面向对象已死”啥的。那么多以前不支持面向对象的语言(比如php/JavaScript)都在尽力的往对象上面靠,就是一个明证。当然,学习面向对象,最好还是通过纯粹的、原生支持面向对象的语言,比如C#和Java,强烈建议通过JavaScript学习面向对象——太残太拧太伤心……
其次,大家要明白“面向对象”要解决的问题,或者它使用的场景。面向对象并不适用于你在学习各种语言语法时写的那些Demo程序(比如“冒泡排序”“图书/课程管理系统”啥的),甚至于大多数的小型开发项目(比如普通的企业网站、个人博客)都不适合。面向对象适合的是那些业务逻辑复杂(其实用“繁杂”更恰当一些)的大型项目。所谓繁杂,繁指多,杂指乱,项目“杂乱”,可以表现为:功能多改动多,所以代码量大、开发人员多、开发/维护跨度时间长……
这个我接下来还要继续讲,但大家先一定要有这个意识。不然你老是用“面向对象”套你那几个小项目,怎么抽象怎么封装,肯定会越整越晕。小项目里,“面向对象”没用,体现不出来“面向对象”的那些好处——这也还是为什么我一开始就讲“不建议新手去‘深入’理解面向对象”的原因,这个阶段,你接触的项目规模有限,对代码复杂性的理解有限,很难体会“面向对象”的作用。
最后,我给大家勾勒出理解面向对象的几个层次,由浅入深,大家可以依次理解。
1、学会面向对象的语法。类的声明和继承、接口和抽象类、方法和属性、访问修饰符……这个没啥说的,非常简单,都应该掌握。
2、想明白为什么会出现“类”。我推荐如何通俗易懂地举例说明“面向对象”和“面向过程”有什么区别?里匿名用户的高赞回答,简单的说,函数太多,要分“类”管理。这就够了,然后在实际开发工作中,试着把类分好,清晰有条理就可以了。
3、明白“对象”是方法(函数)和数据的组合。因为如果你只停留在第2点的理解上,所有的类其实就是静态类,所有的方法都是静态方法。但类的一大特点,就是它自身是包含数据的,而且不同的数据可以造就不同的实例(对象)。你看,直到这个时候,我们才能说面向对象,而不是面向类。
4、开始“继承”。注意,从这里开始,就可能有陷阱了。继承实际上带来了两个结果:重用和多态。重用非常好理解,子类能够使用父类所有非私有的属性和方法嘛,所以很多同学一使用继承,就奔着“重用”去了。比如狗有四条腿,猫也有四条腿,那就抽象出一个有四条腿的父类:动物……但这样做的问题是:桌子也有四条腿,咋整?由于事物之间复杂的共性/特性关系,很容易就整出多重继承出来,比如你开始是这样构想的:

v2-7c6df05f1e3f456a55c7f4fc7ad3777c_720w.jpg

一切都非常美好,但是,接下来“鸭子”怎么办?你觉得它应该是禽类,但是请注意,它也是会游泳的(代码里需要这个功能)。同理,还有公鸡,它也可以产肉,又该怎么办?还有漂亮的画眉,就是用来观赏的,咋整?动物越来越多,这个体系就崩溃了……
所以这里其实是可以批评“面向对象”的第一个点,或者层面。但是,永远不要因为一门技术有这样那样的问题,就轻易的放弃。随着你学习的深入,你可以有更深层次的理解。
5、用组合实现重用,用继承实现多态。这实际上是对第4条的一次“修补”(注意:不是“颠覆”)。我个人认为,这其实是“设计模式”的基础或者核心。对于初学者而言,理解到这里就差不多了;要讲起来,也非常非常的难了。这几乎上升到一种“艺术”的范畴了,好吧,飞哥承认,我自己对此的理解——理解可能是理解了,但应用起来还是捉襟见肘,不是很溜。就像你知道了很多公式,一样解不出一道数学题一样。
问题在哪里?我称之为“复杂度守恒”。有的同学或者听说过“‘面向对象’的设计能够降低复杂度”……但实际上,并没有。业务逻辑的复杂度永远是不可能降低的,除非你改需求;需求就是那样了,所以复杂度就在哪里了,你怎么降低?无论是面向对象,还是设计模式,和不面向对象编程(比如结构化编程)相比,其本质是把复杂度转移到类的关系复杂度上。
我感觉我好像又说得深了一点?就再说一点就停,可能有同学知道工厂模式,能够干掉丑陋的switch...case...,但是,switch...case...这种逻辑,真的消失了吗?没有啊!同学,它不过是通过类的继承和多态实现了呀。你觉得if...else...嵌套非常复杂,但数不清的类的关系一样复杂啊!
我说这些,如果你是新人,可能根本体会不到。可能if...else...嵌套的复杂都还体会不到,就不用说其他了。所以,就此打住吧。我觉得新人能够掌握第3个层次,理解到第4个层次,摸到第5个层次的边,就非常非常不错了。

可能有些同学看了4和5,会觉得:那“面向对象”就确实没有价值啊!就算是做到了第5个层次,也不过是“转移”了复杂度而已。既然if...else...的嵌套和子类父类一样复杂,我干嘛要选择子类父类这种复杂呢?
Good question!
我能给你最简单的回答,两个原因:
1、“人脑”的局限。面对复杂事物,人脑的自然处理方式就是“抽象”和“屏蔽细节”。
假设你现在是一个元帅,要指挥一场战役,你怎么指挥?是不是只会下达一个简单的命令:第十四军必须在15日以前占领23号高地?至于十四军如何占领这个高地,兵力怎么部署、火力怎么配置、需要什么样的后勤资源……一堆的细节问题,你是不是只能忽略掉?
2、从“代码写给电脑看”到“代码是给人看”的转变。
在计算机发展的初期,程序非常的简单,电脑也无法理解高级的复杂的——实际上就是“类自然语言”的指令,程序员大量的工作是把需求“翻译”成电脑能够理解和执行的低级指令,比如石器时代的二进制打孔、汇编和C语言等等,形象的说就是“手把手”的教电脑如何操作,可以具体到“分配32个字节的内存”“存储到CPU的寄存器”这种粒度。
这种方式原始低效,根本无法满足日益增长的软件开发需求,一个最有效对接解决方式就是:把翻译(编译)的工作交给电脑自己去做,给程序员腾出时间和精力解决业务逻辑需求。所以,编程语言变得越来越“高级”越来越类似于人类自然语言。
其实,结构化编程的if...else...已经很接近人类语言了,但这还不够。于是,“面向对象”应运而生。语言是思维的载体:结构化语言,对应的仍然是具体的、一步一步执行性的思维;面向对象,对应的是抽象的、以目标为导向不论细节的的思维!
仍然以战役指挥为例,面向过程,大概就是:

  1. 32门火炮轰击地方阵地5分钟
  2. 16名士兵配合2辆坦克向前冲锋
  3. 1架直升机提供空中支援

面向对象就是:
第二连占领地方阵地。
怎么占领?第二连自己去实现!
于是很多初学者就接受不了,心里是悬着的,他老是要去想:第二连究竟是怎么占领这个阵地的呢?最关键的是,这个实现过程最后还是得他自己去写,所以他本能的就抗拒,或者说迷糊:进行面向对象的封装啊抽象啊啥的,脱了裤子放屁,多此一举嘛!O(∩_∩)O~

一不小心又写了这么多。但是呢,效果怎么样,我心里也是悬着的。所以,回到之前说的,我还是不建议初学者深究“面向对象”,以后,有了工作经验有了团队分工合作接触了大型项目,自然而然地就会逐渐明白:“面向对象”是被逼出来,而不是设计出来的!这一点,其实非常重要。

最后,给大家两张图:

还没有软装床垫薄了,等着,海绵/棕垫正在路上

飞哥的“一起帮·源栈”http://ASP.NET全栈培训,小班教学,拎包入住。
开业酬宾,折上再打折,有兴趣的同学加QQ群:729600626,等着你来撩,^_^


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK