当我开始使用一种面向对象的语言(Java)时,我几乎就成了“酷”并开始编码。在阅读了许多有关OOP的问题之后,直到最近我才真正考虑过它。我得到的总体印象是人们对此感到挣扎。既然我没有这么难过,也不会说我是个天才,所以我想我一定错过了一些东西或误解了。
为什么OOP难以理解?是很难理解?
当我开始使用一种面向对象的语言(Java)时,我几乎就成了“酷”并开始编码。在阅读了许多有关OOP的问题之后,直到最近我才真正考虑过它。我得到的总体印象是人们对此感到挣扎。既然我没有这么难过,也不会说我是个天才,所以我想我一定错过了一些东西或误解了。
为什么OOP难以理解?是很难理解?
Answers:
我个人发现OOP的机制相当容易掌握。对我来说,最困难的部分是它的“为什么”。当我第一次接触它时,它似乎是寻找问题的解决方案。我认为大多数人都很难找到这几个原因:
恕我直言,从一开始就讲OO是一个糟糕的主意。过程编码不是“坏习惯”,而是某些工作的正确工具。无论如何,OO程序中的各个方法往往看起来很程序化。此外,在足够好地学习过程编程以使其局限性变得明显之前,面向对象对学生似乎没有太大用处。
在真正掌握OO之前,您需要了解数据结构和后期绑定/高阶函数的基础。如果您甚至不了解构造数据的概念,而不是仅仅使用基元并传递高阶函数,就很难理解多态性(基本上是传递指向数据的指针和一堆对数据进行操作的函数)指向函数的指针。
设计模式应该被视为面向对象的基础知识,而不是更高级的东西。设计模式可以帮助您从树上看森林,并给出OO可以简化实际问题的相对具体示例,并且您将最终希望以任何方式学习它们。此外,一旦您真正了解了面向对象,事后看来,大多数设计模式都会变得显而易见。
Cat
继承自的类并从Mammal
我们将按程序编写的真实程序中获取真实示例,这无济于事或无益。就像一个简单的数据结构。
我认为有些因素尚未提及。
首先,至少在一切都是对象的“纯OOP”(例如Smalltalk)中,您必须将思维转变为一种相当不自然的配置,以将数字(仅举一个例子)视为智能对象,而不是只是一个值-因为在现实中,21
(例如)真的是只是一个值。一方面,当您被告知OOP的一大优势是更紧密地建模现实时,这变得尤其成问题,但是您首先要从看起来像LSD启发的视图中看到很多东西,甚至是LSD的最基本和最明显的部分。现实。
其次,OOP中的继承也不是很遵循大多数人的思维模式。对于大多数人而言,最明确的分类方法没有接近创建有效的类层次结构所需的绝对规则的任何地方。特别是,创建class D
从另一个继承的class B
意味着class D
共享对象绝对,绝对地共享的所有特征class B
。class D
可以添加自己的新特征和不同特征,但必须保持所有特征class B
不变。
相比之下,当人们从心理上对事物进行分类时,他们通常会遵循更为宽松的模型。例如,如果一个人对构成一类对象的规则制定了一些规则,那么只要遵循了足够多的其他规则,几乎可以打破任何一个规则。即使是一些不能真正打破的规则,也几乎总会被“拉伸”一点。
仅举例来说,将“汽车”视为一类。很容易看出,大多数人认为“汽车” 的绝大多数都有四个轮子。但是,大多数人都看过(至少是照片)只有三个轮子的汽车。我们中的一些年龄合适的人还记得80年代初(或大约20年代)有六个轮子的赛车-依此类推。这基本上给了我们三个选择:
关于OOP的教学通常侧重于建立巨大的分类法-例如,这将是地球上所有已知生命或此顺序上的某些事物的巨大层次结构。这带来了两个问题:首先,也是最重要的是,它倾向于导致许多人专注于与眼前的问题完全无关的大量信息。在某一时刻,我看到了关于如何为狗的品种建模的漫长讨论,以及(例如)“微型贵宾犬”是否应该继承“全尺寸贵宾犬”,反之亦然,或者是否应该有一个抽象的基础“贵宾犬”类,其中“全尺寸贵宾犬”和“微型贵宾犬”都继承自它。他们所有人似乎都忽略了该应用程序应该用于跟踪狗的许可证,
其次,也是非常重要的一点,它导致关注于项目的特征,而不是关注对当前任务很重要的特征。它导致对事物进行建模,真正需要的地方(大部分时间)是构建满足我们需求的最简单模型,并使用抽象来适应必要的子类以适应我们已经构建的抽象。
最后,我再说一遍:多年来,我们正在缓慢地遵循数据库采用的相同路径。早期的数据库遵循分层模型。除了只关注数据之外,这是单一继承。在很短的时间内,一些数据库遵循了网络模型-本质上与多重继承相同(从这个角度来看,多个接口与多个基类并没有什么不同,足以引起注意或关注)。
但是,很久以前,数据库很大程度上都集中在关系模型上(尽管它们不是SQL,但在此抽象级别上,当前的“ NoSQL”数据库也是关系型的)。关系模型的优点是众所周知的,因此在这里我不再赘述。我只是注意到,我们在编程中与关系模型最接近的类比是泛型编程(很抱歉,尽管名称如此,但Java泛型实际上并没有真正的资格,尽管它们在开发过程中迈出了很小的一步。正确的方向)。
OOP要求具有抽象思考的能力;很少有人真正拥有的礼物/诅咒。
我认为您可以这样总结基本的困难:
// 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”并不是一个巨大的飞跃。但是,要很好地处理这些对象并创建它们,您必须颠倒通常的思维方式。
我们不是在操纵对象,而是告诉对象实际上是自己做事情。也许不再感到困难,但是告诉窗口自己打开听起来很奇怪。那些不习惯这种思维方式的人必须不断地与这种奇怪作斗争,直到最终它以某种方式变得自然。
对于大多数人而言,任何范例都需要一定的“边缘”推动才能掌握。根据定义,这是一种新的思维方式,因此它需要一定程度的放开旧观念,并需要一定程度的完全掌握新观念为何有用的原因。
我认为很多问题是,用于教计算机程序设计的方法通常很差。OOP现在非常普遍,以至于它不那么引人注目,但是您仍然经常在函数式编程中看到它:
重要概念隐藏在奇数名称后面(FP:什么是单子?OOP:为什么有时将它们称为函数和方法)?
奇怪的概念用隐喻来解释,而不是按照它们的实际用途,为什么使用它们,或者为什么有人曾经想使用它们来解释(FP:单子是太空服,它包装了一些代码。OOP:对象就像鸭子一样,可以发出声音,走路并从Animal继承)
好的东西因人而异,因此对于任何学生来说,引爆点还不是很清楚,而且通常老师甚至都不记得了。(FP:哦,monad使您可以在类型本身中隐藏某些东西并继续下去,而不必每次都明确地写出正在发生的事情。OOP:哦,对象使您可以使用该数据保留某种数据的功能。)
最糟糕的是,正如问题所表明的那样,有些人会立即意识到为什么这个概念很好,而有些人则不会。这实际上取决于转折点是什么。对我而言,掌握对象存储数据和该数据的方法是关键,在此之后,其他所有内容都可以自然扩展。然后,我后来跳了起来,就像意识到从对象进行方法调用与以该对象作为第一个参数进行静态调用非常相似。
稍后会有所帮助,以帮助增进理解,但这是使一个人摆脱“ OOP没有意义,人们为什么要这么做”的最初原因。“ OOP是最好的,为什么人们还要做其他事情?”
我在大多数情况下不同意dsimcha的回答:
从头开始讲面向对象本身并不是一个坏主意,讲过程语言也是如此。重要的是,我们要教人们写清晰,简洁,有凝聚力的代码,而不管面向对象还是程序性的。
好的OO程序中的单个方法根本不会成为程序性的。随着OO语言的发展(阅读C#,因为除C ++以外,我才知道这是唯一的其他OO语言)以及它们的语法越来越复杂(lambda,LINQ到对象等),这变得越来越正确。程序语言中的OO方法和过程之间唯一的相似之处是每种方法的线性本质,我怀疑这种变化很快就会改变。
您也不能在不了解数据结构的情况下掌握过程语言。指针概念对过程语言和对OO语言一样重要。例如,通过引用传递参数(这在过程语言中很常见)要求您理解指针,就像学习任何OO语言一样。
我认为根本不应该在面向对象编程的早期就教授设计模式,因为它们根本不是面向对象编程的基础。在不了解设计模式的情况下,绝对可以成为一名优秀的OO程序员。实际上,一个人甚至可以使用众所周知的设计模式,甚至不知道它们以适当的名称记录下来,也没有写过关于它们的书籍。应当从根本上讲授设计原则,例如单一职责,开放关闭和接口隔离。不幸的是,如今,许多认为自己是面向对象程序员的人要么不熟悉这个基本概念,要么只是选择忽略它,这就是为什么我们那里有那么多垃圾OO代码的原因。
要回答原始发布者的问题,是的,OO是比过程编程更难理解的概念。这是因为我们没有考虑现实生活对象的属性和方法。例如,人的大脑不会轻易将“ TurnOn”视为电视的一种方法,而是将其视为人类打开电视的功能。类似地,对于人类大脑来说,多态性是一个陌生的概念,通常只通过一个“面孔”看到每个现实对象。再次继承对我们的大脑来说不是自然的。仅仅因为我是一名开发人员,并不意味着我的儿子会成为一名开发人员。一般来说,需要对人脑进行学习以学习OO,而过程语言则更自然。
您应该阅读Objects Never?好吧,几乎没有。Mordechai Ben-Ari(需要ACM成员资格)认为OOP如此困难,因为它不是对任何事物建模的自然范式。(尽管我对此文章有所保留,因为尚不清楚他认为程序是使用OOP范式而不是使用OO语言的程序范式编写的,他认为程序需要满足什么条件。)
面向对象编程本身并不难。
困难的部分在于做好。在代码之间放置剪切的位置,以便可以轻松地将内容移动到通用基础对象,并在以后进行扩展?如何使您的代码可被其他人使用(扩展类,包装代理,重写方法),而无需跳过箍。
那是很难的部分,如果做得对,可能会非常优雅,如果做得不好,可能会非常笨拙。我个人的经验是,它需要大量的练习已经在所有的地方,你会希望你做的不同的情况下,才能做的不够好这个时间。
我只是看了理查德·费曼(Richard Feynman)的一段视频,该视频讨论了人们在思考时实际上可能完全不同的方法论—我的意思是完全不同。
当我进行高级设计时,我碰巧将对象可视化,可以看到它们,看到它们的界面以及看到信息需要遍历的路径。
我也很难记住细节,并发现OO是一种很好的组织帮助-与浏览松散组织的子例程列表相比,查找功能要容易得多。
对我来说,OO是一个很大的好处,但是如果您不以相同的方式可视化或不执行高级体系结构,则它可能毫无意义且令人讨厌。
INSTR
),因为该名称已附加到类型(如string::find
)上
在介绍给OO之前,我已经做了相当多的GW-Basic和Turbo Pascal编程,所以最初它是DID。
不知道这是否会发生在其他人身上,但是对我而言,就像这样:我对编程的思考过程纯粹是过程性的。如:“这样的事情会发生,然后接下来的事情会发生”,等等。我从不认为变量和数据只是程序流程中短暂的参与者。编程是“行动的流程”。
我想不容易理解(现在看来如此愚蠢)是这样一种想法,即数据/变量实际上真正重要,其意义远不只是在程序“流程”中短暂地扮演角色。或者换种说法:我一直试图通过发生的事情来理解它,而不是通过什么是它,这是掌握它的真正关键。
我不难理解,但是可能很多程序员对这个概念感到陌生,它们来自过程语言。
从我所见/读到的很多人(至少在论坛中)来看,他们在向OOP寻找“结果”。如果您是不回头修改程序扩展代码的过程程序员,那么可能很难理解其好处。
另外,那里有很多糟糕的OOP,如果人们正在阅读/看到它们,那么很容易理解为什么他们会感到困难。
IMO,您需要等到它“点击”或由真正有知识的人教过,我认为您不能着急。
我认为许多人都难以理解OOP的原因是这些工具并没有真正促进它。
今天的计算机语言是计算机中正在发生的事情的抽象。
OOP是一种表示抽象的抽象方法。
因此,我们正在使用抽象来构建具有抽象的抽象。除此之外,我们抽象的内容通常是非常复杂的物理/社交交互,而且,难怪。
实际上,我有一个名为“面向对象编程的斗争”的博客,它源于我在学习它方面的一些挣扎。我认为这特别难理解,因为我花了很多时间使用过程编程,而且我很难理解这个想法,即对象可以由一组属性和行为表示(我习惯于只是变量和方法的集合)。
另外,有很多概念使语言面向对象-继承,接口,多态性,组成等。在真正有效地编写代码之前以及在面向对象中,确实有很多关于它的理论需要学习。方式,而在过程编程中,这仅仅是了解诸如为变量分配内存以及对其他方法的入口点调用之类的问题。
动机。当您不知道为什么时,以及当您无法看清所做的事情并弄清楚自己是否做对时,很难学到一些东西。
需要的是使用OO来做有用的事情的小型项目。我建议浏览一本有关设计模式的书,并提出一本显然有用并且与OO兼容的书。(我曾经尝试过使用Strategy。像Flyweight或Singleton之类的东西会是错误的选择,因为它们通常是使用对象的方式,而不是使用对象来完成任务。)
我认为这取决于年龄(年龄作为经验的代表),更重要的是兴趣。如果您“年轻”(也许是绿色的),并且从未想过其他任何方式,那么这似乎很简单。另一方面,如果您认为这是您所见过的最酷的东西-28岁时发生在我身上或类似的东西-很容易gr。
另一方面,如果您认为,就像我的许多Java学生所做的那样,“我们为什么要学习它,这只是一时的风尚”,几乎是不可能学习的。大多数技术都是如此。
无论选择哪种范例(OOP,功能等),为了编写计算机程序,您都需要知道程序将执行哪些步骤。
定义流程的自然方法是写下其步骤,对于较大的任务,可以将任务分解为较小的步骤。这是程序的方式,这是计算机的工作方式,这是您逐步检查清单的方式。
OOP是另一种思维方式。您无需考虑需要逐步完成的任务清单,而是想到对象,对象的能力和关系。因此,您将编写许多对象,小的方法,并且程序将神奇地工作。为此,您需要改变主意...
这就是为什么OOP很难实现的原因。由于所有事物都是一个对象,所以他们要做的就是要求其他对象做某事,而这些其他对象基本上就是做某事。因此,OOP程序中的控件可以在对象之间疯狂地来回跳转。
作为目前正在学习编程并且在这一领域有一些问题的人,我认为这个概念的具体实现并不难理解。我之所以这样说是因为我有了OOP的想法,并且已经在PHP中使用了大约一年,但是当我转向C#并查看其他程序员对对象的用法时,我发现很多人都在这样做我只是不明白。正是由于这一点,我才得以更好地理解OOP原理。
当然,我意识到这个问题很可能是我缺乏使用本机OOP语言的经验,并且随着时间的流逝,我将找到新的方法来利用对象,这对于新程序员来说就像我本人一样不清楚。目前正在经历。杰里·科芬(Jerry Coffin)谈到了几次,特别是在他的评论中:
一方面,当您被告知OOP的一大优势是更紧密地建模现实时,这变得尤其成问题,但是您首先要从看起来像LSD启发的视图中看到很多东西,甚至是LSD的最基本和最明显的部分。现实。
我发现这是非常准确的,因为看到某人为不是真的东西创建类时,我经常会得到这种印象-一个具体的例子使我无所适从,但我能即时想到的最接近的距离是一个对象(下次看到引起相同混乱的东西时,我将进行编辑)。有时,OOP似乎暂时不理会自己的规则,变得不那么直观。当对象正在生成对象,从封装它们的类继承等时,这种情况通常不会发生。
我认为对于像我这样的人,将对象的概念视为具有多个方面会有所帮助,其中之一包括在某些情况下不会像对待对象一样对待对象。诸如距离之类的东西,仅在范式上稍有变化,就可以作为一个理论对象遇到,但是却不能握在手中。我必须认为它具有一组属性,但是具有一组更为抽象的行为,例如访问其属性。我不是很确定这是我理解的关键,但似乎是我目前的研究处于领先地位。
对我而言,主要的跃迁只是了解OOP的抽象概念。现在我对编程非常陌生,现在我已经进行了一年半的编程,所以我对OOP的介绍是使用Actionscript和Processing。当我第一次学习Actionscript编码时,它不在OOP中。我学会了直接在“动作”面板中进行编码,这就是我学习编程的基本原理(变量,函数,循环等)的方式。因此,我了解到它是直接在Flash或Processing阶段做些事情。
当OOP出现时,意识到我可以在一个对象内创建方法和属性以使其能够使用和重用,这对我来说首先很难理解。一切都非常抽象并且难以处理,但是编程语言本身要好得多,但是首先建立这些连接需要一种信念的飞跃。
良好的OOP理解=良好的导师或书籍或两者兼有+个人兴趣+练习。
从我的个人经验来看,个人利益在指导员或好书或两者兼而有之的正确输入下,是跨过程序编程到OOP的漫长道路。
更好地了解OOP的最好朋友就是练习。这肯定会提高您的OOP能力。
俗话说:“没有什么可以代替辛勤的工作,没有成功的捷径。”
祝好运!