[关闭]
@Sarah 2015-05-28T14:12:58.000000Z 字数 5147 阅读 1461

什么是面向对象的编程?

知乎相关问题节选

OO更多的是给了你一种能力,一种忽略细节的能力:忽略的越多,人类有限的智力就可以容纳越多越复杂的问题,并由此提高生产效率。

在面向对象出生之前,有一个面向过程的人,它将整个待解决的问题,抽象为描述事物的数据以及描述对数据进行处理的算法,或者说数据处理过程。当问题规模比较小,需求变化不大的时候,面向过程工作得很好。
可是(任何事物都怕“可是”二字),让问题的规模越来越大越来越复杂,需求变化越来越快的时候,面向过程就显得力不从心了,想象一下,当你根据需求变化修改了某个结构体,你不得不修改与之相关的所有过程函数,而一个过程函数的修改,往往又会涉及到其他数据结构,在系统规模较小的时候,这还比较容易解决,可是当系统规模越来越大,涉及到多人协作开发的时候,这肯定是一场噩梦。这就是那场著名的软件危机。
为了解决这场软件危机,面向对象应运而生了(有问题的出现,必然就有解决问题的方法的出现,英雄人物大都是这样诞生的)
我们知道,面向对象的三板斧分别是封装,继承和多态,他用封装将问题中的数据和对数据进行处理的函数结合在了一起,形成了一个整体的对象的概念,这样更加符合人的思维习惯,更利于理解,自然在理解和抽象一些复杂系统的时候也更加容易。他用继承来因对系统的扩展,在原有系统的基础上,只要简单继承,就可以完成系统的扩展,而无需重起炉灶。他用多态来应对需求的变化,统一的借口,却可以有不同的实现。
可以说,面向对象思想用他的三板斧,在一定程度上解决了软件危机,我想这是他重要性的根本体现。

大家都知道,面向对象的三大特性“封装、继承、多态”,但个人认为其中的“封装”是面向对象的最核心的特点。
究其原因,主要是“封装”让一个人可以理解的系统范围可以变得更广,可以让我们“更好的理解和抽象”我们所看到的世界。

OOD更好的映射(抽象)了现实与程序设计,而程序设计在解决现实问题的时候本身就是把现实问题最终映射(抽象)成了数学逻辑来运算。当然,一些OOD相关的特性,例如继承、封装、多态、接口等等除了提高程序的抽象能力,还提高了课维护性。

此处输入图片的描述

把一组数据结构和处理它们的方法组成对象(object),把相同行为的对象归纳为类(class),通过类的封装(encapsulation)隐藏内部细节,通过继承(inheritance)实现类的特化(specialization)/泛化(generalization),通过多态(polymorphism)实现基于对象类型的动态分派(dynamic dispatch)。

面向对象是一种以[你办事我放心]为理想构造出来的东西。这也是一个很好的鉴别一个面向对象的设计是否正确的方法。一个好的面向对象设计,会让你让他办事的时候,你不得不放心(也就是说,你不放心也没用,反正你什么都不知道)。如果你不放心就不能让他办事,那多半证明你可能是那种需要haskell的程序员。

用一句话来说就是:面向对象是对人类基于自然语言的知识组织方式的简化模拟。
去年曾有人写文章说“对象已死”,俺当时就反对,面向对象至少30年不会死,至少在人类可以用自然语言编程之前不会死,也就是说,只要还需要专门的“编程”语言,面向对象就必然存在。
众所周知,面向对象的语言和编程方法适合编写应用程序,不适合编写系统程序(操作系统内核、设备驱动、通信协议、数据库、虚拟机等等),也不适合编写科学计算程序和算法库,有没有想过是为什么?
这其中是有规律可循的,适合用面向对象语言和方法开发的软件,通常都有比较多的用文字表述的需求说明,而较少需要使用数学符号和公式,较少需要使用图形来辅助表达,而且这类软件通常需要处理很多人机交互操作;那些不适合面向对象方法开发的软件,往往都需要较多的数学、图形来辅助表达需求,否则就难以说明,这类软件往往人机界面较少。之所以如此,根本在于,面向对象是有利于利用人类知识当中,可以用语言表达的那一部分知识的编程思想和工具,语言逻辑可以比较容易地转换成面向对象的程序代码。面向对象的思路,和人类用语言组织知识的思路一脉相承,在计算机不能够理解自然语言的时代里,人类需要这样一种思路和方法,把自然语言知识转换为计算机程序。

让软件世界更像现实世界

面向对象的做法,其实就是按照“把复杂问题化简为单个的小问题”一般性工作思路,将程序要解决的问题切分为相对独立的实体,已达到理清其中关系明确任务边界的目的

有事不要自己干,要让对象去干。

如果上帝是程序员,他怎么创造世界上的所有动物。
理解这个问题就理解了面向对像

凡是思维的建立都要靠练习。你要建立完整的面向对象思维,就得通过完整的面向对象的程序的开发来练习。我写了这么多年程序,发现最符合这一点的就是——你自己去造一个GUI库。等你造到你觉得满意了,很多年过去了,面向对象的思维早就烂熟于胸,化为本能。

这是个循序渐进的过程。
我更推荐 理论->实践->理论,的节奏来提高自己,首先看看标准的书籍,不用深读,然后去做一个项目、第一步先实现需求、第二步在去重构项目重构的过程中在利用和深究理论上的东西。

面向对象只是一种模式,软件工程其实还有很多好玩的模式去研究,路漫漫其修远兮。。

本人非计算机专业,软件方面只是个人爱好,现在在一家软件公司工作。开始跟你一样,代码写的一坨,真的不想看第二遍,后来看了相关的开源项目,代码规范,慢慢的好点了,知道怎么样增强代码的扩展性,怎么提高程序的可读性。虽然现在的代码在看了第五遍,第六遍依然会感觉是一坨,但是比以前好多了。所以推荐你去codeproject,Google code上面看看你感兴趣的开源项目,相信你会有所收获的。

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
例如五子棋,面向过程的设计思路就是首先分析问题的步骤:
1、开始游戏,2、黑子先走,3、绘制画面,4、判断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤2,9、输出最后结果。
把上面每个步骤用分别的函数来实现,问题就解决了。
而面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为:
1、黑白双方,这两方的行为是一模一样的,2、棋盘系统,负责绘制画面,3、规则系统,负责判定诸如犯规、输赢等。
第一类对象(玩家对象)负责接受用户输入,并告知第二类对象(棋盘对象)棋子布局的变化,棋盘对象接收到了棋子的变化就要负责在屏幕上面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定

1是个对象, 1.toString() 是个方法 1.tag 是个属性

tree 是个对象, tree.grow()是个方法. tree.height是个属性.

一切都是对象.

面向对象和面向过程并不是编程的区别,而是设计的区别。

如果说面向过程就是强调一步一步,那对象里的method,也是一步一步写,所以我不认同字面上去解释面向过程。

面向对象其实就是三点,
封装(encapsulation),
继承(Inheritance),
多态(polymorphism)。

这不是我总结的,而是C++ Primer如果我没记错的话,第十五章?还是第几章我不记得了,反正是全书第二次介绍OOP的章节开篇讲的(第一次是第七章这个我记得),我觉得总结的很经典。

这三点的意思我就不啰嗦了。无非是,

封装,一切皆class的原因,任何程序,都要封装好,provide接口就行了,好用且安全。

继承,书中给的一句话的解释是,让我们在设计相似的东西时更加方便。

多态,书中给的一句话的解释是,我们在使用类似的东西的时候可以不用去思考它们微弱的不同。

基于这三点,OOP,至少我个人的理解,OOP仅此而已。我们关心的不是过程,而是接口,而接口来自对象,故名为面向对象。

曾经的C++面向对象老师来添个答案。

不管你学什么语言,一开始都只是学语法,试着让你写的东西能在电脑上跑起来。仅此而已。不用想太多。

至于面向对象,是一种写作思路,跟语言关系不大。大学里学C++做为面向对象入门,是因为你学过C了呀。语法什么的已经不是你的阻碍。

思路这种东西嘛,你可以先囫囵吞下去。领悟还是要靠后期自己多coding ,遇到实际问题就会发现面向对象之美了。

最后给一个中肯的建议。
不用把学习目的定在“学好面向对象”这种空洞的事情上。最好是做一些自己感兴趣的事情。
今年可以先制订个目标,比如做个吃货网站公布出来(现在各种云服务很便宜的)。明年再订个目标,做个配套app出来。让亲戚朋友都来用。你会很有成就感的。

这样等你毕业的时候,不论是找工作还是找合伙人还是找投资人,都是一个可见的成果。

而且在不停的开发实践中,面向对象这种技术也能迎刃而解。

最后,祝所有学开发的同学一路顺风!

完蛋了。OO的动作对应的是状态,才不是数据。OO的精髓在我看来,在于你使用动作的时候碰不到状态,至于数据,永远都不应该跟动作一起写到一个类里。只处理数据的东西,就是一个普通的函数,跟类毛关系都没有。
类是什么,类就是一个构造interface实例的构造函数。类本身最好甚至都不要直接引用,引用接口就好了。接口就是能力,不是单纯的动作。譬如说【我会啪啪啪】就是一个接口,至于我啪啪啪有多少个做法,这是里面的一个个的动作。那我啪啪啪的时候到底经历了什么心理【状态】,你们是永远也不知道的。
这就是封装。
那么多人总是捧着一个对OO错误的理解就开始喷,失望极了,对你们。

假设我们是上帝,要创造世界,因为这个过程太过复杂,无从入手,所以先从一件简单的事情看起。现在我们要设计一个方法,用于描述狼吃羊这个事情,某只狼吃了某只羊,你可以面向过程地吃,eat(狼A, 羊A),也可以面向对象地吃,狼A.eat(羊A)。差别在哪里?只是写法有点变化。

好,那么我们帮上帝模拟整个生物界,这里面很多东西可以吃,大鱼吃小鱼,小鱼吃虾米,吃不吃皮,吐不吐骨头,这个时候再来修改这个eat函数,复杂吗?eat里面要判断很多东西,假如上帝很勤劳,所有代码都自己设计,那没关系,没太大区别,判断就判断呗。

假设上帝没足够精力来管理整个东西了,雇了一群天使来协助设计,每个人都来修改这个eat函数,当然可以拆分,wolfEatSheep(), tigerEatWolf(),然后在eat里面判断参数来分别调用,把函数分下去让每个人做,可以。
动物不光要做吃这个事情,要能跑能跳,会说会叫,又多了一堆函数,每个里面都这么判断,相当相当的烦。怎么办?我们来面向对象一下。

现在开始按照动物拆分,100个天使,每个天使创造一种动物。创造哪种动物,就站在哪种动物的角度考虑问题,我吃的时候怎么吃,跑的时候怎么跑,都跟别人无关,这么一来,每个人就专注多了。每个动物只关注我要怎么才能活着,不必站在上帝的角度考虑问题。这个过程,是类的划分过程,也就是封装的过程。

这时候,上帝觉得自然界光有动物是不行的,还要有植物,刚才说的这些都是动物,植物的特点跟动物有很大区别。假设你是上帝,为每种生物安排衣食住行,那是相当复杂的。偷懒吧,上帝说,植物们,你们自己生长吧,动物们,你们吃喝玩乐吧,假如能达到这个效果,那很省事。

上帝用一个循环来遍历所有动物,让他们吃喝玩乐,用另外一个循环让植物欣欣向荣。动物跟植物为什么要区别对待?因为它们不是同样的东西,能做的事情不同。所有动物派生于动物这个基础类型,从动物这个种类下,又分出各种纲,各种目,各种属。狮子是哺乳动物,猴子也是,但是狮子是猫科动物,猴子是灵长动物,这就构成了一个倒着的树状体系,一层一层形成继承关系。哺乳动物会喂奶,那么所有继承自哺乳动物的,都自动拥有这个特征。整个这一切,构成了继承链。

假设有一天由于变异出现了新物种,不必劳烦上帝关照,只要鉴别一下它属于什么类型,就知道能做什么事了,它的一举一动,都必然拥有它所继承的种类的特征。

这样就能描述生物界了吗?不,还有那么一些怪胎的存在。你认为哺乳动物都不会飞,那就错了,因为蝙蝠会飞。蝙蝠会飞是它自身的特性,并非继承自哺乳动物,但是“飞”这个动作,却非蝙蝠独有。如果把“飞”定义成接口,那就很美好了,蝙蝠实现了它的飞行接口,虽然内部实现跟鸟类有所不同,而且这并不影响它的哺乳动物特性。

总之,是否面向对象只是思维方式的不同。做一个软件,面向对象也能做,不面向对象也能做。我的观点,如果关注可维护性和协作性,从目前的角度,面向对象是很好的选择,它很自然,很优雅,优雅得只要打一个“.”,你就能想起来什么事能做,什么事不能做。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注