笔记: :这个问题是从 博客帖子 我几个月前写了。在将博客的链接放在 评论 在程序员上,有人要求我在这里发布一个问题,以便他们可以回答。这篇文章是我最受欢迎的,因为人们似乎在Google中输入了“我没有以对象为导向的编程” 很多. 。随时在这里回答,或在WordPress的评论中回答。

什么是面向对象的编程?没有人给我一个令人满意的答案。我觉得您不会从周围说“对象”和“面向对象”的人的鼻子中得到一个很好的定义。除了面向对象的编程外,您也不会从做过的人那里得到一个很好的定义。没有人了解程序性和面向对象的编程,曾经让我对面向对象的程序的实际作用有一个一致的想法。

有人可以给我他们对面向对象编程的优势的想法吗?

有帮助吗?

解决方案

将软件视为计算机内部存在的机器或装配线。一些原材料和组件被馈入机器,并遵循一组将它们处理为最终产品的程序。设置该过程以在某些原材料或组件上对特定顺序(例如,时间,温度,距离等)执行特定的操作。如果要执行的操作细节不正确,或者机器的传感器无法正确校准,或者某些原材料或组件不在预期质量标准之内,则可能会改变操作的结果,并且产品不会出现。正如预期的。

这样的机器的操作非常严格,并且可以接受。机器不会质疑设计师的智能或当前的操作环境。只要指示它,它将继续遵循程序。即使更改原材料或组件可能会对以后操作发生的情况产生巨大影响,机器仍将执行其程序。该过程需要进行审查,以查看对程序进行了哪些更改,以补偿和产生所需的结果。对产品的设计或配置的更改也可能需要对执行的操作或订单进行重大更改。尽管负责生产的人很快就学会了尽可能多地隔离操作以减少它们之间的不良影响的重要性,但在处理处理时,有很多对条件组件的假设是在处理过程中的;直到最终产品在某些不同的操作环境中用户手中,可能无法检测到的假设。

这就是程序编程的样子。

对象 - 方向提供的是消除组件状况的假设的一种方法;因此,要在该组件上执行的操作以及如何将其集成到最终产品中。换句话说,OOP就像获取处理某些特定组件并将其交给较小机器的过程详细信息。负责该过程的较大机器告诉特定于组件的机器,该机器的操作期望完成,但为特定于组件的机器处理的步骤提供了细节。

至于对象方向比非对象的软件的优势:

  • 特定于组成的行为 - 详细介绍如何处理特定组件的较小组件特定机器的责任可确保任何处理组件的时间,其机器将适当地做到;
  • 多态性表达 - 由于特定于组件的机器执行针对其特定组件的操作,因此发送给不同机器的相同消息的作用可能不同;
  • 类型抽象 - 对于几种不同类型的组件,将相同的词汇用于其机器所做的操作通常是有意义的;
  • 关注点分离 - 将组件特定的细节留在其机器上意味着该过程机器只需要处理其过程的更一般性,更大的问题及其管理所需的数据即可。另外,受其他组件变化影响的可能性较小。
  • 适应性 - 专注于其专业领域的组件可以通过更改其使用的组件或使其可用于另一台流程机的组件来适应不可预见的使用;
  • 代码重复使用 - 焦点狭窄且适应性更高的组件可以通过更频繁地使用来利用其开发成本。

其他提示

从您的博客中,您似乎熟悉命令和功能性编程,并且您熟悉面向对象的编程所涉及的基本概念,但是您从来没有真正拥有过它的“单击”使其有用。我将尝试用这些知识来解释,并希望它对您有所帮助。

从本质上讲,OOP是一种使用命令式范式来通过创建对问题域进行建模的“智能”数据结构来更好地管理高度复杂性的方法。在(标准的程序性非对象)程序中,您有两个基本内容:变量和代码知道该如何处理它们。该代码从用户和其他各种来源获取输入,将其存储在变量中,在其上运行,并生成输出数据,这些数据与用户或其他位置有关。

面向对象的编程是一种通过采用基本模式并以较小规模重复程序来简化程序的方法。就像程序是大量的数据集合一样,代码知道该怎么做,每个对象都是与代码绑定的一小部分数据,知道该如何处理它。

通过将问题域分解为较小的部分,并确保尽可能多的数据直接绑定到知道该如何处理的代码,您可以使整个过程以及子 - 副本的推理变得更加容易构成流程的问题。

通过将数据分组到对象类中,您可以集中与该数据相关的代码,从而使相关代码更容易找到和调试。通过封装访问说明符背后的数据,并仅通过方法(或属性,如果您的语言支持它们)访问它,您可以大大减少数据损坏或违反不变性的潜力。

通过使用继承和多态性,您可以重复使用先前的类,自定义它们以适合您的特定需求,而无需修改原件或从头开始重写所有内容。 (这是一个 你永远不应该做的事情, ,如果您可以避免它。)请小心您了解基本对象,否则您可能会出现 杀手袋鼠.

对我而言,这些是面向对象的编程的基本原理:复杂性管理,代码集中化和通过创建对象类,继承和多态性的创建问题域建模,以及通过使用封装和封装和控制权力而提高安全性,而没有牺牲权力或控制权。特性。我希望这可以帮助您理解为什么这么多程序员认为它有用。

编辑:回答乔尔在评论中的问题,

您能否解释一个与命令式程序根本不同的“面向对象的程序”包含的内容(除了您概述的这些精美的定义)?您如何“让球滚动?”

这里有一点免责声明。我的“面向对象程序”的模型基本上是Delphi模型,它与C#/。网络模型非常相似,因为它们是由前Delphi团队成员创建的。我在这里说的话可能不适用于其他OO语言。

面向对象的程序是所有逻辑围绕对象构成的程序。当然,这必须在某个地方引导。您的典型Delphi程序包含初始化代码,该代码创建一个名为单身对象 Application. 。在程序开始时,它会调用 Application.Initialize, ,然后打电话给 Application.CreateForm 对于您要从一开始就加载到内存中的每种形式,然后 Application.Run, 它在屏幕上显示主表单,并启动构成任何交互式计算机程序的核心的输入/事件循环。

应用程序和表格民意调查从OS传入事件,并将其转换为对象上的方法调用。很常见的一件事是使用事件处理程序或在.NET语言中使用“委托”。一个对象的方法说:“做X和Y,但还检查是否分配了此特定事件处理程序,并在此调用。”事件处理程序是一种方法指针 - 一个非常简单的闭合,包含对该方法的引用和对对象实例的引用 - 用于扩展对象的行为。例如,如果我的表单上有一个按钮对象,我通过连接OnClick事件处理程序来自定义其行为,这会导致其他对象在单击按钮时执行方法。

因此,在面向对象的程序中,大多数工作都通过定义具有某些职责的对象并通过方法指针或一个对象直接调用在另一个对象的公共接口中定义的方法来完成。 (现在我们又回到了封装。)这是一个想法,我在大学上大学上课之前没有任何背部概念。

我认为OOP基本上只是一个名字,您可能会像我一样愿意做一些事情。

早在我还是婴儿程序员的时候,即使在Fortran中,也有一个指向子例程的指针。能够将指针传递给子例程作为参数的指针到另一个子例程真的很有用。

那么,下一步将真正有用的事情是将指针存储在数据结构的记录中。这样,您可能会说唱片“知道”如何自行进行操作。

我不确定他们是否曾经将其建立到Fortran中,但是在C及其后代很容易做到这一点。

因此,在下面,即使有些人将其变成了充满可怕的流行语的巨型潮流,即使您将其变成了一个巨大的潮流,这是一个简单而有用的想法,您可能会很容易做到自己,并且更容易使用。

有各种各样的OO系统,很难获得每个人都会同意的定义。我没有尝试显示Java的OO与通用LISP对象系统的相似之处,而是从更常规的逐步开始。

假设您有很多作为散射数据存在的对象。例如,点可能是x,y y和z数组中的元素。为了考虑一个要点本身,将所有数据将所有数据拉到C中是有意义的 struct.

现在,对于任何数据对象,我们都将数据全部结合在一起。但是,在程序程序中,代码分散了。假设我们正在处理几何形状。绘制形状的功能很大,需要了解所有形状。找到区域的功能很大,另一个用于周长。圆的代码通过多个函数散布,为了添加另一种类型的形状,我们需要知道要更改哪些功能。在面向对象的系统中,我们将功能收集到相同的事物中(class)作为数据。因此,如果我们想查看所有圆形代码,它在那里 Circle 定义,如果我们想添加一个 Quartercircle 我们简单地编写其班级,并拥有代码。

一方面受益于我们可以维护班级不变的,这是班级的每个成员的真实事物。通过将类外部的代码限制在直接与类数据成员混乱的情况下,我们拥有所有可以在一个地方更改类数据的代码,我们可以确认它不会做任何棘手的事情(例如,有一个带有一条腿的三角形比其他两个组合更长)。这意味着我们可以依靠类的每个成员的某些属性,而不必检查每次使用它是否理智的观察。

主要好处是继承和多态性。通过将所有这些形状定义为一个名为的类的子类 Shape, ,我们可以操纵代码 Shapes,这是形状子对象的工作,可以执行操纵所要求的任何事情。这意味着,当我们添加新形状或完善较旧形状的行为时,我们不需要触摸旧的测试代码。我们会自动拥有可以直接利用新代码的旧代码。与其让控制代码了解所有不同可能的形状,不得不维护所有不同形状的功能,我们只是处理形状及其属性,同时保持 Shape 子类。这简化了控制代码。

我们在这里有几个优势。由于我们有类别不变的,因此我们可以以相同的方式来推理大型数据对象,这意味着我们通常可以将复杂概念分为简单的概念。由于圆形代码主要包含在 Circle, ,我们的当地增加了。由于没有一个圆圈散布在不同地方的几个不同功能的概念,因此我们之间的耦合较少,而不必担心将它们保持同步。由于实际上是类型的类,因此我们可以利用现有类型系统来捕获不兼容的类型。

oo具有许多不同的定义,是的。我敢肯定,您可以自己找到很多。我个人喜欢 里斯回复:哦 作为理解它们的一种方式。我猜想您已经读过Paul Graham以来已经读过。 (我将其推荐给对OO感兴趣的任何人。)我将在这里或多或少地采用Java定义{1,2,3,7,8,9}。

OO实用程序的问题,尤其是我处理的方式,值得几千行代码(部分是为了不仅仅是一堆断言)。但是,这是该假设文件的摘要。

我认为OO在小规模上没有非常有用,大约几百行。特别是,没有良好功能影响的OO语言往往会使使用任何类型的收藏或任何需要多种数据类型的内容完成简单的事情确实很痛苦。这是大多数设计模式发挥作用的地方。 他们是基础语言低功能的创可贴.

在大约一千行中,很难跟踪所有操作和数据结构及其之间的关系。在这一点上,有助于明确组织数据结构和操作,绘制模块边界和定义职责,并具有方便的方法来理解这些定义时,它可以在这一点上有所帮助。

Java-ish OO是解决这些问题的中途解决方案,这些问题恰好赢得了受欢迎程度。因为这是Java人适用于由功能不足的语言造成的小规模问题的机制,所以它往往看起来像是对所有事物的神奇解决方案,而不仅仅是保持井井有条的方式。熟悉功能编程的人倾向于喜欢其他解决方案,例如CLOS或HASKELL的类型类,或者在粘在C ++中时模板元编程,或者(像我一样,每天在C#中工作)使用OO,但对此并不感到兴奋。

OOP试图根据对象及其之间的相互作用来建模现实世界的概念。作为人类,我们倾向于用物体来处理世界。世界上充满了具有某些属性的对象,并且可以与其他对象进行互动之类的事情。 OOP允许以类似的方式对世界进行建模。例如,

  • 人是一个对象。一个人具有一些特性,例如年龄和性别。一个人可以做事:吃饭,睡觉,开车。
  • 汽车也是一个对象(尽管类型不同)。它还具有诸如Make,Model和年份之类的属性。汽车可以做事:移动。

但是汽车不能自行移动,它需要一个人来驱动它 - 对象之间的相互作用。

OOP =数据结构 +消息传递 +继承,所有这些都是编程模型中的逻辑演变。

大约90秒内可以(程序员)理解OOP(有关链接,请参见我的个人资料)。这些概念非常简单。

如何应用是另一回事。仅仅因为您知道如何挥舞锤子并不意味着您知道如何设计和建造房屋。 ;-)

不久前,我写了一篇博客文章,您可能会发现很有帮助: 程序与OOP解释.

我第一次理解的方式是:

在面向对象的编程之前,您已经 结构化编程. 。一切都集中在过程中。您要问自己的第一个问题是我想处理这些信息?".

使用面向对象的编程,它围绕数据。您要问自己的第一个问题是我需要处理的女巫信息?“。这使抽象更容易。

由于您了解结构,并且了解功能指针,并且您可以从功能指针中理解结构,因此,从您的角度来看,我将面向对象的编程定义为“简单的编程,大量使用具有函数指针的结构”。它仍然是传统意义上的编程 - 所有数据和代码都在数据上。区别仅仅是如何定义所有这些信息以及如何将其定义。

也许过于简化的是,传统编程是“代码,具有一些数据结构”,而面向对象的编程是“数据结构,带有某些代码”。两者仍然都有数据结构,并且都有代码。因此,面向对象的编程无非是预先定义数据类型的行为,并为它们通过一组函数进行通信的合同执行合同。

正如您所观察到的,有一类巨大的应用程序,这不是实施解决方案的好方法。您似乎生活在一个主要由此类应用程序组成的世界中。在您的博客文章中,您提到了“ 99瓶啤酒”问题的实现(您最喜欢的编程展示柜”)。 99瓶啤酒无疑是该类别的一部分。试图通过查看99瓶啤酒的实现来理解面向对象的编程,就像试图通过看树屋来了解高层建筑。即使是一个非常精美的树屋,也只能教您很多。

TL; DR:OO编程就像传统编程一样,除了您将更多的精力集中在预先定义数据结构上,并且您的数据结构通过函数指针相互通信。

我认为Wikipedia页面是获取基本面的好地方:
http://en.wikipedia.org/wiki/object-oriented_programming

基本上,想法是,OOP试图改进的程序编程的重点是建模的过程。 OOP转移到了您正在建模的“事物”上的重点,这些事物的过程和数据都包含在这些事物中。

因此,例如,假设您正在设计一个应用程序来跟踪任务列表。在过程编程中,模型中的顶级实体将是发生的过程,例如创建任务,删除任务,更改任务信息等。在OOP模型中,您将专注于创建任务,并且考虑该任务应负责的数据和过程。然后专注于其他对象任务应与之交互的内容,例如,如果您想保留有关任务的注释,则可能是笔记或其他内容。

我希望这会有所帮助。只需继续阅读并查看代码,它将突然“单击”。那是我的经历。

许可以下: CC-BY-SA归因
scroll top