it-swarm.cn

为什么OOP很难?

当我开始使用一种面向对象的语言(Java)时,我几乎就成了“酷”并开始编码。在阅读了许多有关OOP的问题之后,直到最近我才真正考虑过它。我得到的总体印象是人们对此感到挣扎。既然我没有那么难过,也不会说我是个天才,所以我想我一定错过了或者误会了。

为什么OOP难以理解?Is很难理解?

93
gablin

我个人发现OOP的原理相当容易掌握。对我来说最困难的部分是它的“为什么”。当我第一次接触它时,它似乎是寻找问题的解决方案。我认为大多数人都很难找到这几个原因:

  1. 恕我直言,从一开始就教OO是一个糟糕的主意。过程编码不是“坏习惯”,而是某些工作的正确工具。无论如何,OO程序中的各个方法往往看起来很程序化。此外,在充分学习过程编程以使其局限性变得明显之前,OO对学生来说似乎不是很有用。

  2. 在真正掌握OO之前,您需要了解数据结构和后期绑定/高阶函数的基础。如果您甚至不了解构造数据的概念,而不是仅仅使用基元并传递高阶函数,就很难理解多态性(基本上是绕过指向数据的指针和一堆对数据进行操作的函数)指向函数的指针。

  3. 设计模式应该被视为面向对象的基础知识,而不是更高级的东西。设计模式可以帮助您从树上看森林,并提供OO可以简化实际问题的相对具体示例,并且您最终将希望学习它们。此外,一旦您真正了解了OO,大多数设计模式在事后就会变得显而易见。

120
dsimcha

我认为有些因素尚未提及。

首先,至少在“纯OOP”(例如Smalltalk)中,其中everything是一个对象,您必须将思维转换为一个相当不自然的配置才能想到一个数字(仅举一个例子) )作为智能对象,而不仅仅是一个值-因为实际上21(例如)实际上is只是一个值。当一方面您被告知OOP)的一大优势是对现实进行更紧密的建模,但是首先从看起来像LSD启发的视图开始时,这变得尤其成问题。甚至是现实中最基本,最明显的部分。

其次,在OOP)中的继承也不是很严格地遵循大多数人的思维模式。对于大多数人而言,最明确地进行分类的做法是not接近绝对规则的任何地方创建有效的类层次结构所必需的,特别是创建从另一个class D继承的class B意味着class D的对象绝对绝对共享allclass B的特征。class D可以添加自己的新特征和不同特征,但是allclass B的特征必须保持完整。

相比之下,当人们从心理上对事物进行分类时,他们通常会遵循更为宽松的模型。例如,如果一个人对构成一类对象的规则制定了一些规则,那么只要遵循了足够多的其他规则,几乎可以打破任何一个规则。即使是一些不能真正打破的规则,也几乎总会被“拉伸”一点。

仅举例来说,将“汽车”视为一类。很容易看出,大多数人认为“汽车”的vast具有四个轮子。但是,大多数人都看过(至少是照片)只有三个轮子的汽车。我们中的一些年龄合适的人还记得80年代初(或大约20年代)有六个轮子的赛车-等等。这基本上给了我们三个选择:

  1. 不要断言汽车有多少个轮子-但这会导致隐含的假设,即它永远是4,并且代码可能会破坏另一个数字。
  2. 断言所有汽车都有四个轮子,即使我们知道它们确实是四个轮子,也要将其他轮子归为“非汽车”。
  3. 设计该类以允许改变车轮数量,以防万一,即使很有可能永远不需要,不会使用或经过适当测试此功能。

关于OOP)的教学通常侧重于建立巨大的分类法-例如,将是地球上所有已知生命的巨型层次结构的零碎碎片,或按此顺序排列的事物。这引发了两个问题:首先,它往往会导致许多人专注于与眼前的问题完全无关的大量信息。有一次,我看到了关于如何为狗的品种建模以及(例如)“微型贵宾犬”应该继承“全尺寸贵宾犬”,反之亦然,或者是否应该有一个抽象的“贵宾犬”基类,“全尺寸贵宾犬”和“微型贵宾犬”都应该继承。可以忽略的是,该应用程序应该用于跟踪狗的许可证,并且出于手头的目的,只有一个名为“品种”(或该顺序的名称)的字段而无需对关系进行建模就足够了在所有品种之间。

其次,也是非常重要的一点,它导致关注于项目的特征,而不关注于对当前任务很重要的特征。它导致对事物进行建模,而在大多数情况下,真正需要的是构建最简单的模型来满足我们的需求,并使用抽象来适合必要子类来满足需求。我们建立的抽象。

最后,我再说一遍:我们慢慢地遵循数据库多年来采取的相同路径。早期的数据库遵循分层模型。除了专门关注数据之外,这是单一继承。在很短的时间内,一些数据库遵循了网络模型-本质上与多重继承相同(从这个角度来看,多个接口与多个基类并没有什么不同,足以引起注意或关注)。

但是,很久以前,数据库很大程度上都集中在关系模型上(尽管它们不是SQL,但在此抽象级别上,当前的“ NoSQL”数据库也是关系型的)。关系模型的优点众所周知,我在这里不再赘述。我只是注意到,我们在编程中关系模型的最接近的类比是泛型编程(很抱歉,但是尽管名字叫Java泛型,例如,实际上并没有资格,尽管这是朝正确方向迈出的一小步)。

57
Jerry Coffin

OOP要求具有抽象思维的能力;很少有人真正拥有的礼物/诅咒。

26
John Kraft

对于大多数人来说,任何范例都需要一定的“超越边缘”才能掌握。根据定义,这是一种新的思维方式,因此它需要一定程度的放开旧概念,并需要一定程度的完全掌握新概念为何有用的原因。

我认为很多问题是,用于教计算机程序设计的方法通常很差。 OOP现在非常普遍,以至于它不那么引人注目,但是您仍然经常在函数式编程中看到它:

  • 重要概念隐藏在奇数名称后面(FP:什么是单子?OOP:为什么有时将它们称为函数和方法)?

  • 奇怪的概念用隐喻来解释,而不是按照它们的实际用途,为什么使用它们,或者为什么有人曾经想使用它们来解释(FP:单子是太空服,它包装了一些代码。OOP:物体就像鸭子一样,可以发出声音,走路并从Animal继承)

  • 好东西因人而异,因此对于任何学生来说,引爆点还不是很清楚,而且通常老师甚至都不记得了。 (FP:哦,monad使您可以在类型本身中隐藏某些东西并继续下去,而不必每次都明确地写出正在发生的事情。OOP:哦,对象使您可以使用该数据保留某种数据的功能。)

最糟糕的是,正如问题所表明的那样,有些人会立即意识到为什么这个概念很好,而有些人则不会。这实际上取决于转折点是什么。对我而言,掌握对象存储数据和该数据的方法是关键,在此之后,其他所有内容都可以自然地扩展。然后,我后来跳了起来,就像意识到从对象进行方法调用与以该对象作为第一个参数进行静态调用非常相似。

稍后会有所帮助,以帮助增进理解,但这是使一个人摆脱“ OOP毫无意义,为什么人们这样做的原因”的最初原因。 “ OOP是最好的,为什么人们还要做其他事情?”

21
CodexArcanum

我认为您可以这样总结基本的困难:

// The way most people think.
Operation - object - parameters
// Example:
Turn the car left.

// The way OOP works conceptually
Object - operation - parameters
// Example:
Car.Turn(270);

当然,人们可以习惯将“ left”映射为270,是的,说“ Car.Turn”而不是“ turn the car”并不是很大的飞跃。但是,要很好地处理这些对象并创建它们,您必须颠倒通常的思维方式。

我们不是在操纵对象,而是告诉对象实际上是自己做事情。也许不再感到困难,但是告诉窗口自己打开听起来很奇怪。那些不习惯这种思维方式的人必须不断地与这种奇怪作斗争,直到最终它以某种方式变得自然。

21
John Fisher

因为OOP的基本解释与它在现场的使用方式几乎没有任何关系。大多数教学该程序的程序都尝试使用物理模型,例如“想一想汽车一个对象,轮子作为对象,以及门和传动装置……”,但是在一些模糊的模拟编程案例之外,对象更多地用于表示非物理概念或引入间接。效果是它使人们以错误的方式直观地理解它。

通过设计模式进行教学是描述OOP的一种更好的方法,因为它向程序员展示了如何用对象有效地攻击一些实际的建模问题,而不是抽象地描述它。

15
Dan Monego

我在大多数情况下不同意dsimcha的回答:

  1. 从一开始就教OO本身并不是一个坏主意,过程语言也不是教。重要的是,我们教人们写清晰,简洁,有凝聚力的代码,而不管OO或程序。

  2. 好的OO程序中的单个方法根本不会看起来是程序上的。随着OO语言的发展,这变得越来越真实(请阅读C#,因为除了C++之外,这是唯一的OO我知道的语言)),而且它们的语法每天都在变得越来越复杂(lambda,LINQ到对象等)。OO程序语言中的方法和过程是每种方法的线性性质,我怀疑这会很快改变。

  3. 您也不能在不了解数据结构的情况下掌握过程语言。指针概念对于过程语言和OO语言)一样重要。例如,通过引用传递参数(这在过程语言中很常见)要求您尽可能多地了解指针。学习任何OO语言。

  4. 我认为完全不应该在OO编程)中早期讲授设计模式,因为它们根本不是OO编程的基础。一个人可以肯定地成为一个好OO)程序员,不了解任何设计模式。实际上,一个人甚至可以使用众所周知的设计模式,甚至不知道它们以适当的名称记录下来,并且书籍是应该从根本上讲授诸如单一职责,打开关闭和接口隔离之类的设计原则。不幸的是,许多人认为自己OO这些天,程序员对此并不熟悉基本概念或只是选择忽略它,这就是为什么我们在那里有很多垃圾OO)代码。只有在对这些原则和其他原则有透彻了解之后,才应引入设计模式。

要回答原始发布者的问题,是的,OO)比过程编程更难理解。这是因为我们没有考虑现实生活对象的属性和方法。例如,人类大脑不会轻易将“ TurnOn”视为电视的一种方法,而是将其视为人类打开电视的功能。类似地,多态性对于人脑来说是一个陌生的概念,通常只看到一个物体就可以看到每个现实对象。再次继承对我们的大脑来说并不自然。仅仅因为我是一名开发人员,并不意味着我的儿子就会成为继承人。一般而言,需要训练人脑学习OO程序语言对此更为自然。

13
SoftwareRockstar

我认为许多程序员在进行前期设计和计划时会遇到困难。即使有人为您完成所有设计,仍然有可能脱离OOP原则。如果我采用一堆意大利面条代码并将其转储到类中,那真的是OOP吗?不懂OOP)的人仍然可以使用Java进行编程。而且,不要将理解的困惑与不愿意遵循某种方法或不同意它相混淆。

6
JeffO

您应该阅读 Objects Never?好吧,几乎没有。 (Mordechai Ben-Ari)(需要ACM会员资格)建议OOP如此困难,因为它不是对任何事物进行建模的自然范例。 (尽管我对此文章有所保留,因为尚不清楚他认为程序是使用OOP范式编写的,而不是使用OO语言的程序范式编写的,他认为程序需要满足什么条件。 )

5
Ken Bloom

面向对象编程本身并不难。

困难的部分在于做好。在代码之间放置剪切的位置,以便您可以轻松地将内容移动到通用基础对象,并在以后进行扩展?如何使您的代码可被其他人使用(扩展类,包装在代理中,覆盖方法),而不用无所事事。

这是很难的部分,如果做得正确,可能会非常优雅;如果做得不好,则可能会非常非常笨拙。我的个人经验是,在所有希望您以不同方式进行操作的情况下,都需要进行大量练习,才能使此操作足够好 this 时间。

5
user1249

在介绍给OO之前,我已经对GW-Basic和Turbo Pascal进行了相当不错的编程,所以最初它[〜#〜] did [〜#〜]投入了我的精力。

不知道这是否会发生在其他人身上,但是对我而言,就像这样:我对编程的思考过程纯粹是过程性的。如:“发生某事,然后发生某事”,等等。我从不认为变量和数据只是程序流程中短暂的参与者。编程是“行动的流程”。

我认为不容易掌握(就像现在看起来那样愚蠢)的想法是,数据/变量实际上是真实的东西,从更深层次的意义上讲,不仅仅是在节目“流程”中短暂的演员。或换种说法:我一直试图通过什么发生,而不是通过什么来理解它,这是真正掌握它的关键。

4
Bobby Tables

我只是看了理查德·费曼(Richard Feynman)的一段视频,该视频讨论了人们在思考时实际上可能完全不同的方法论—我的意思是完全不同。

在进行高级设计时,我碰巧将对象可视化,可以看到它们,看到它们的界面以及看到信息需要遍历的路径。

我也很难记住细节,发现OO)是一种出色的组织帮助,比通过松散组织的子例程列表进行扫描更容易找到功能。

对我来说OO是一个很大的好处,但是如果您不以相同的方式可视化或不执行高级体系结构,则可能毫无意义且令人讨厌。

4
Bill K

我认为很难理解,但是可能很多程序员对这个概念感到陌生,它们来自过程语言。

从我所见/读到的很多人(至少在论坛中)来看,他们在向OOP寻找“结果”。如果您是不回头修改程序扩展代码的程序程序员,那么可能很难理解其好处。

而且,那里有很多不好的OOP=),如果人们正在阅读/看到它,那么很容易明白为什么他们会感到困难。

IMO,您需要等到它“点击”或由真正有知识的人来教我,我认为您不能匆忙。

3
DBlackborough

我认为对许多人来说OOP很难)的原因是,这些工具并没有真正促进它。

今天的计算机语言是计算机中正在发生的事情的抽象。

OOP是一种表示抽象的抽象方法。

因此,我们正在使用抽象来构建具有抽象的抽象。除此之外,我们提取的内容通常是非常复杂的物理/社交交互,而且也就不足为奇了。

3
ElGringoGrande

我实际上有一个名为“面向对象编程的斗争”的博客,它源于我在学习它方面的一些努力。我认为我很难理解,因为我花了很多时间使用过程编程,而且我很难理解这个想法,即对象可以由一组属性和行为表示(我习惯于只是变量和方法的集合)。

另外,有很多概念使语言面向对象-继承,接口,多态性,组成等。在真正有效地编写代码之前以及在面向对象中,确实有很多关于它的理论需要学习。方式,而在过程编程中,这仅仅是理解诸如变量的内存分配以及对其他方法的入口点调用之类的问题。

2
Tim Claason

动机。当您不了解原因以及当您无法看清所做的事情并弄清楚自己是否做对了时,很难学习一些东西。

所需要的是使用OO=做一些有用的事情的小型项目。我建议浏览一本有关设计模式的书,并提出一个显然有用并且可以与OO很好地结合使用的书。我曾经尝试过使用Strategy。像Flyweight或Singleton之类的东西会是错误的选择,因为它们通常是使用对象的方法,而不是使用对象来完成任务。)

2
David Thornley