面向对象的编程真的可以模拟现实世界吗?[关闭]


52

我已经看到,通常情况下,面向对象的编程都是基于对真实世界的建模,但是是吗?

在我看来,业务层以外的任何事物都不是真的。我的GUI类/数据访问类在现实世界中没有任何模型。即使在我的业务层,我也有一些类,例如观察员,经理,工厂等,这些类并不是真实的对象。我尝试设计类以利用诸如封装之类的优势,但是现实世界是否被封装?

虽然我创建的某些对象正在对真实世界的对象进行建模,但OOP之前的代码会不会做到这一点?我怀疑OO是第一个在其代码库中包含诸如Customer之类的概念的人的。但是OO确实是关于如何对事物建模的方法,而这种建模方法对我来说似乎并不受现实世界的启发。

那么:面向对象的编程真的可以为现实世界建模吗?


85
使用表示现实世界对象的OOP对象的类比的想法是“向儿童撒谎”概念的主要示例。我们告诉刚开始学习OOP的人这个谎言,因为这是获得基本知识的直观方法。一旦他们了解了这些基础知识,他们就准备好吸收他们所知道的一切都是错误的事实。实际上,事情要复杂得多。就像学校的物理学一样:拳头掉落,然后被吸引到更大的物体上,然后大的物体弯曲空间,最后,我们被告知我们实际上对事物的运作一无所知。
evilcandybag 2012年

4
这里真正的争论是什么?是否存在一些无法通过OO技术完全建模的现实世界实体?还是建模(即使用简化的理解)无法充分适应世界是一个坏主意,是否行得通?
Dipan Mehta 2012年

1
@DipanMehta,争论在于将OO描述为对现实世界的建模错过了面向对象编程的核心。所有编程技术都(在某种程度上)对现实世界进行建模,这并不是使OO独特的原因。
Winston Ewert 2012年

@WinstonEwert好吧,modeling the real world可能不是真正使OO与众不同的原因。也许。但是我绝对不会相信您也不会在OO中执行此操作。您认为哪种范例或技术比OO更好?
Dipan Mehta 2012年

14
所有编程都试图在现实世界中建模。有些范例比其他范例更好地建模了不同的零件。程序代码模型工作流,​​功能代码模型逻辑问题解决,面向对象的代码模型层次关系。汇编语言代码模型很棒
Jesse C. Slicer 2012年

Answers:


50

一点都不。

但是,这种方法确实可以创建一个很好的抽象来保存复杂的数据结构以及一些对数据结构起作用的方法。


答案很简洁。根据定义,您会丢失模型中的一些细节。
MathAttack 2012年

抱歉,我不喜欢这个答案。使用OOP,您可以对现实世界(的某些方面)进行大量建模。
风土

33

任何类型的模型都不能完全模拟真实世界。

他们为选定的部分建模,这些部分与手头的应用程序相关。

您所谈论的(观察员,管理者,工厂等)是可以帮助您正确实现抽象并支持所需功能(例如持久性)的基础结构。


15
我认为“建模”已经意味着要模仿某些方面(而忽略其他方面)。从这种意义上讲,OO允许对现实世界进行建模。
陶Szelei

OO可以很好地建模问题的哪些部分?某些问题无法很好地映射到OO模型,因此想到了气候模型。许多业务问题确实可以很好地映射到面向对象,这就是为什么该模型被广泛使用的原因。
Michael Shopsin 2012年

@MichaelShopsin-您的意思是对问题而不是我的答案发表评论吗?
奥德

@Oded我喜欢你的回答;我的评论是“模型选定部分”的扩展。OO模式为许多问题建模,这是确保它们与当前问题相匹配的问题。
Michael Shopsin 2012年

31

无论如何,模型是什么:
模型是用于解释现实世界系统或事件工作原理的简化表示

面向对象的编程是否允许您对现实世界建模?

肯定是

几乎不可能对系统进行建模以使其完全符合实际情况。

我是否总是必须完全按照实际情况对软件进行建模?

没有

说了可以建模的一切并不意味着您必须对所有模型进行建模。实际上,有用建模的本质是呈现简化表示。简化多少足以表达当前的业务需求,需要省略的是在成功使用该技术与迷失该技术或根本不使用该技术之间的良好平衡。

当然,实际上并不存在某些实体,但是只有通过建模,我们才能真正概念化。


9
什么是模特儿? ”一小撮可怜的私人。但是有足够的代码供您使用!
Ben Brocka'3

我认为您的最后一点是无形的关系。有时对象存在于现实世界中,我们只是看不到它们。
MathAttack 2012年

19

我认为教导名词和类之间存在关系会导致烦人的不良习惯的养成,后来不得不由不耐烦的建筑师或高级工程师来解决。

应该教导的是,这些类就像您的大脑一样对抽象对象进行建模。您脑中有一个“汽车”的抽象概念,它不映射到任何特定的物理汽车,它是可重用的,汽车的特定实现可以从中继承。您的大脑甚至为您提供元模型概念。您对思想是什么,概念是什么有了一个心智模型。

如果我们教会人们识别他们已经在您脑海中生成的模型,那么他们将为构建实际软件做好更好的准备。


+1如此棒极了的观点。多谢分享!我想知道您是否从书本中捡起了书?我绝对会喜欢读那本书的。
Mahdi 2014年

8

... 这个世界比用面向对象的语法可以表达的要丰富。

考虑一下人们普遍用来理解和描述所有系统的一些常见概念,这些概念与对象模型不符。最生动的例子包括“之前/之后”范式,“原因/效果”范式和“系统状态”的概念。实际上,“煮咖啡”,“组装车辆”或“在火星上降落漫游车”的过程不能分解成简单的对象。是的,在OO语言中对它们进行了这种处理,但这是人为的和违反直觉的。例程本身的序列- 在什么条件下基于什么因果关系在什么之前发生-在OO中根本没有有意义的表示,因为OO没有序列,状态或原因的概念。

流程在现实世界和编程中非常普遍。多年来,已经设计出了复杂的机制来处理事务,工作流,业务流程,线程,协议和其他固有的“过程”概念。这些机制试图补偿OO编程中固有的时不变性不足,因此滋生了复杂性。相反,应该通过允许特定于过程的构造(例如``之前/之后'',``原因/效果''以及``系统状态'')作为语言的核心部分来从根本上解决问题...

引用源:Victoria Livschitz,编程的下一步


2
当您看到如此令人信服的案子证明您仍然不同意时,这是一种奇怪的感觉。我得到了报价的动机,很难说出更好的话。我只是不知道以与我们的符号化,面向关系的思维过程相同的方式对问题进行建模是错误的。
令人生畏的2012年

我猜很有趣……但是我从来没有想过编写一个冲泡咖啡的程序。问题本身已经被模糊地定义。该程序是否可以访问硬件执行器,或者这是一个纯模拟?在这两种情况下,对象方法似乎都可以提供一个良好的起点,可以对涉及的执行器进行建模,也可以对涉及的执行器和工具的内部状态进行建模。
Mark E. Haase 2012年

13
this.MoveTo(Environment.Find<Bathroom>().OrderBy(b=>b.Distance(this)).First()); this.SitOn(Environment.Find<Toilet>().Where(t=>!t.IsOccupied).OrderBy(t=>t.Distance(this)).First().Component<Seat>()); this.DiscardWaste(HumanWasteType.All);
亚当·罗宾逊

1
当对它过于狭窄的OO范式提出如此多正确的批评时,很难相信她是Java的拥护者。而且有点荒谬,她没有提到任何使它变得更好的语言(除了“相对于其前身C ++有了巨大的改进。” ...)。
大约

1
OO没有排序或状态的概念。废话 在OOP?oO中没有排序和状态的概念
气候

5

是的,OO通常可以用于对现实世界实体进行建模。

即使在我的业务层中,我也有一些类,例如观察员,经理,工厂等,它们并不是真实世界的对象。

不要将面向对象的开发与设计模式混淆。OO分析和设计是一种对可维护代码进行编程的方法。结合OO语言,程序员可以通过OO的支柱(封装,多态和继承)创建可重用代码。

要封装实体,我们可以根据其真实世界的对应对象对该实体进行建模。例如,如果我们有吉他,那么吉他课将封装现实世界吉他的行为和属性。我们可以进一步将吉他抽象为例如,IInventoryItem通过多态性和继承来利用代码重用的潜力。

另一方面,我们可能会发现一家吉他工厂可以帮助我们维护一组不同类型的吉他。这不是因为OO。相反,工厂是一种经过时间考验的设计模式,是一种成功地为此目的创建可维护代码的行之有效的手段。换句话说,我们的程序员经常在解决类似的问题。因此,我们提出了解决这些问题的通用解决方案(不要重新发明轮子)。

这并不意味着面向对象必须对现实世界进行建模,也不意味着它总是这样做的最佳选择。简而言之,作为一个经验法则,“ OO对现实世界进行建模”是完全合理的。


5

这取决于您在谈论哪个现实世界。

豪尔赫·路易斯·博尔赫斯(Jorge Luis Borges)撰写了一个故事“特隆,乌克巴,奥比斯·特尔蒂乌斯”,其中一个居民民族对现实世界的看法大相径庭:

假想的特隆人民持有极端的伯克利主义理想主义,否认世界的现实。他们的世界被理解为“不是空间物体的并发,而是一系列不同种类的独立行为”。特隆(Tlön)的一种想象语言缺少名词。它的中心单元是“由具有副词作用力的单音节后缀或前缀限定的非人称动词”。博尔赫斯(Borges)列出了与Tlönic相对应的“月亮从水面升起”:hlöru fang axaxaxasmlö,字面意思是“在流经月亮的上游向上”。[...]在特隆的另一种语言中,“基本单位不是动词,而是单音节形容词”,由两个或更多的组合构成名词,“月亮”变成“圆通的黑暗”或“

(摘自维基百科关于这本书的文章)

对我而言,意义不仅仅在于对世界的感知与我们的感知有所不同,这有点陈词滥调,但对现实结构本身的感知取决于我们所使用的语言,无论是自然语言还是编程语言。Tlönese可能对Lisp感到非常满意,并且可能认为Java(又称“名词王国”)非常不自然,而大多数terran程序员倾向于偏向于面向对象而不是功能语言。我喜欢这两种样式,因为我认为这主要是透视问题。有些问题最好用功能性解决,而另一些问题最好采用面向对象的编程技术。优秀的程序员在尝试解决方案之前,总是从不同角度看待难题。或者,正如艾伦·凯(Alan Kay)所说:观点值得80智商点

因此,我对您的问题的回答是:您在谈论哪个现实世界?如何?


“对现实结构本身的感知取决于我们说的语言,无论是自然语言还是编程语言”。真的是这样!
风土

4

虽然我创建的某些对象正在对真实世界的对象进行建模,但是OOP之前的代码会不会这样做?

我不会说。OOP约束了事物(属性/对象)与它们可以/可以对其进行的操作(方法)之间的关系,而过程编程则不这样做(除了使用严格类型时,在一定程度上)。模型不仅是定义离散的零件和过程,还在于定义它们如何组合在一起,OOP在这方面尤其擅长。


我认为您的意思是程序不起作用。
Winston Ewert 2012年

是的,正确。我会更改它
wheresrhys

3

我已经看到它通常重复面向对象编程是基于对真实世界的建模,但是对吗?

是。这里的重点是基于。OOP不会对现实世界建模(如果确实如此,那么顺便说一句),并且不应该这样做。OOP所做的是允许我们像对现实世界建模那样对编程问题进行建模:作为通过我们对行为进行抽象来定义的实体系统。


3
是的,所以它不是 基于对真实世界的建模,对吗?
大约

3

OO代码通常不会为现实世界建模-至少这不是目标,它只是让您以一种更自然的方式思考代码,更像是您对现实世界中事物的思考方式-这就是报价要说的。


3

它并没有为我们的世界建模,但是却为人类对我们世界的解释建模。人类自然会将事物作为对象分开。面向对象技术之所以有效,是因为它允许人们以他们的思维方式进行编程。


2

OOP可能不是现实世界及其中包含的对象的理想模型,但是它是一种有助于应对现实生活软件日益复杂的方法。通过将代码分解为逻辑相关的块,还可以帮助更好地编写代码。

尽管较旧的面向过程的方法肯定也会提供结果,但是OOP可以帮助您更快,相对容易地到达那里,即使在处理大型和复杂项目时也是如此。

抽象和封装有助于专注于问题的核心,同时隐藏实际上使事情发生的所有管道。通过继承,您可以在代码的各个方面之间建立有意义的逻辑关系。多态性可促进代码重用,并让您轻松处理变体(那些“ 现有对象几乎相同的行为”这类经常发生的问题)并通过扩展与对象关联的语义来扩展代码。

我认为OOP更像是一种行之有效的帮助,可以让您有效地应对现实生活系统的所有复杂性。因此,尽管它可能不是真实世界的非常详尽的模型,但它足够接近并且可以帮助您完成工作,而恕我直言最终是最重要的。


2

我已经看到它通常重复面向对象编程是基于对真实世界的建模,但是对吗?

在我看来,业务层以外的任何事物都不是真的。

不,正如您所指出的那样,用OOP语言“建模”的许多事物都是抽象概念,例如消息队列,控制器和堆栈。

即使在您的业务层中,您仍然没有对“真实世界”进行建模。假设您有一个雇员班。员工也是人,也是哺乳动物,又是动物,也是……(打哈欠)员工有自己喜欢的颜色,他们穿某些衣服并相信某些事情。简而言之,现实世界中存在着各种各样的复杂性,我们甚至没有尝试在大多数程序中捕获。

在建模中,我们仅关注对手头任务有意义的模型方面。如果我们正在设计时间输入系统,那么我们可能需要某种Employee类,但是该类不需要属性来表达员工喜欢的颜色。

因此,模型不应尝试(或假装)完全代表“真实世界”。

虽然我创建的某些对象正在对真实世界的对象进行建模,但是OOP之前的代码会不会这样做?我怀疑OO是第一个在其代码库中包含诸如Customer之类的概念的人的。

你是对的。如果您查看的不是OOP的大型程序,它们通常仍围绕数据结构进行组织。出于清楚的原因,数据结构和所有可操作的功能都彼此靠近定义。(subversion项目就是一个很好的例子。数据结构和功能都以模块名称作为前缀,这样可以清楚地知道哪些结构和功能可以相互使用。)

我不是编程语言历史上的专家,但是我认为OOP的产生是偶然的观察,即以这种方式组织代码时代码更清晰,更易于理解,因此语言设计师开始在那种组织类型的地方设计语言。更严格地执行。

OOP和非OOP之间的最大区别是OOP将代码绑定到数据。因此,与其像这样调用代码:

verb(noun);

我们改为这样做:

noun->verb();

尽管这看起来像是语法上的差异,但实际上是在心态上的差异。我们告诉对象要做什么,通常不关心对象的内部状态或工作方式。描述对象时,我们只需要描述它的公共接口即可使用它。


2

面向对象的编程真的可以模拟现实世界吗?

不完全的。

在现实世界中,我们面临着实际问题。我们希望使用一种范式解决该问题,该范式复制我们希望构建的系统,该系统成为模型。

例如,如果手头有一个购物车应用程序的问题,我们有不同的实体,例如

  1. 产品是一个抽象术语,可以包含多个成员,例如图书,小工具和汽车,这些成员可以再次细分。

  2. 像(销售税)这样的税收标准将取决于软件的实施位置,因为该软件会根据政府政策进行更改。

  3. 是根据产品是否与税收标准一起导入考虑。

  4. 用户可能有一个购物车,上面有产品列表等。

因此,正如您所看到的,我们正在尝试解决一些实际问题,但将这些问题模块化为OOP范例,以使其尽可能接近实际系统。


1
我喜欢这个答案。OO应该在为您的问题领域建模,因此,尽管有很多现实世界的概念与您要解决的问题无关,但是您将拥有OO构造,这些构造无法准确地映射回现实世界,但它满足了问题领域的需求。
2012年

2

我认为您对本意是平淡无奇,历史悠久的声明的理解过多。OO编程,类,多态性,虚拟函数等许多思想是在1960年代以Simula语言引入的(http://en.wikipedia.org/wiki/Simula)。顾名思义,Simula被设计为用于编写模拟的语言。因此,从历史上看,是的,引入了面向对象的思想来努力为“现实世界”建模。它们是否比其他样式更成功,尚有争议。


2

虽然我创建的某些对象正在对真实世界的对象进行建模,但是OOP之前的代码会不会这样做?

OOP和OOP之前的代码之间的最大区别在于,前者将现实世界建模为一组相互交互的不同实体,每个实体在执行功能上具有有限的“权力”,并且还能够“做出反应”具有自己动作的外部事件。后者将所有事物建模为一大堆数据,它们本身并不做任何事情,而计算则代表“正在发生的事情”,并且会影响其中的任何一个或全部。

是否更好地模拟现实世界,这实际上取决于您要模拟世界的哪个方面。例如,如果您要描述一个物理模拟,则您要描述被周围的物体点燃的火可能会产生的影响,因此最好用“传统”方法来表示,因为光和热都很好,定义的过程会影响其他对象的内部和外部状态,并且不会根据每个特定对象的行为而变化,而仅受其属性影响。

另一方面,如果您正在建模交互相互作用以产生所需行为的不同组件,则将它们视为代理而不是被动的事情可以使正确操作更容易,而不会丢失任何内容。如果要打开电视,只需按一下按钮,如果拔下电源线,TV.turnOn它将为我检查一下。因此,没有转动齿轮的风险,而忘了转动其他与之接触的齿轮,因为齿轮本身(如果编程正确)将负责由于主齿轮而引起的次要交互作用。

但是OO确实是关于如何对事物建模的方法,而这种建模方法对我来说似乎并不受现实世界的启发。

我认为,这与我们对世界的看法有关,而不是与世界的实际情况有关。有人可能会争辩说,一切都只是一堆原子(或能量,或波浪,等等),但这无助于我们完成处理所面临问题,了解周围环境并预测未来事件的任务(或描述过去的内容)。因此,我们建立了世界的“心理模型”,通常这些心理模型比“数据+处理”模型更能与OO对应-可以说它“更好地”模拟了现实世界的实际运行方式。

有趣的是,大多数人都将OOP视为“经典OOP”的同义词,在该类中,我们通过分类学来创建事物的集合和子集,并将对象明确地放置在非常特定的集合中。这对于创建可重用的新类型非常有用,但是当您要建模的实体几乎是独立的并且在启动与其他对象的交互时,很少(如果有的话)是交互的目标,那么就不是很好。或更糟糕的是,当该实体的实例很少(也许只有一个)时,或者实例的组成,行为或两者差异很大。

但是,还有“原型OOP”,其中通过选择一个相似的对象并枚举它们不同的方面来描述一个对象。我建议这篇文章是对思想过程的很好且不是太技术的解释(即使对于史蒂夫·耶格(Steve Yegge)的标准,整个文章也太大了,所以我要指向相关的部分:P)。再次,这与我们的心理模型很好地匹配,当通过与已知实例进行比较来想象未知实例时,却不一定是现实世界的“工作原理”……(即使我们意识到它们,两头母牛实际上是完全分离的实体)在很多方面都是“相同”的)


1

我认为“确实”是这个问题的重要部分。我认为面向对象的编程当然可以对现实世界的“对象”进行建模,但这就是编程。有没有不能被滥用的方法,所以我不认为这是公平地说,“OOP并不模拟真实世界”仅仅因为你可以做愚蠢的事情的对象。这比说指针不安全是不公平的,因为您可以使用指针来做愚蠢的事情。

维基百科关于此事的文章总结得很好:

真实世界的建模和关系
OOP可用于将真实世界的对象和过程与数字对象相关联。但是,并非所有人都同意OOP可以促进直接的真实世界映射(请参见“负面批评”部分),或者真实世界的映射甚至是一个值得的目标。伯特兰德·迈耶(Bertrand Meyer)在面向对象的软件构造[21]中指出,程序不是世界的模型,而是世界的某些部分的模型。“现实是堂兄两次被删除”。

关键是,除非您的程序是Universe模拟,否则您只关心真实世界的某些部分-因此称为“模型”。这就是模型的用途,它们为您提供了需要显示的结构和功能。

在现实世界中,我们拥有事物(对象),事物可以执行动作(方法)。我们可以量化事物的各个方面(属性)。当以简化的方式使用时,OOP有各种潜力可以模拟现实世界中的事物。每个复杂的事物都有更小或更具体的子类,并且所有这些事物都通过方法具有自然的交互作用。

OOP是一种抽象方法,所以实际的事情是OOP是否真的在现实世界中对对象进行逻辑建模,而不是对所有可能做的每件事都没有进行建模的重要性就不那么重要了。如果您需要做所有可能的事情,那么您实际上并不是在建模


1

为了在适当的上下文中考虑面向对象,让我们上移一个抽象级别,然后大体谈一下编程,好吗?

无论您采用面向对象还是功能性方法,程序都必须执行某些操作,不是吗?该程序的重​​点是在给定一定刺激的情况下展现某些行为。因此,程序之所以存在,是因为它们做了一些事情。这里的关键词是行为

除了考虑程序必须执行的行为之外,您的程序通常还需要表现出一定的素质。例如,对于心脏监测器程序来说,满足其所需的行为是不够的-它通常还需要足够快的性能才能近乎实时地运行。程序可能需要表现出的其他“品质”是:安全性,灵活性,模块化,可扩展性,可读性等。我们称这些架构质量属性。因此,可以说我们的程序需要满足某些行为(功能)目标以及表现出某些素质(非功能)。

到目前为止,这还没有涉及OO。现在开始吧。

一旦工程师理解了需求(行为,AQA,约束等),就会出现问题:我应该如何组织我的代码,使其能够完成所有需要做的事情,同时还表现出成为有用程序所必需的质量?面向对象编程是一种将程序功能组织到协作对象的内聚模块中的策略。函数式编程只是组织程序功能的另一种策略,它以不同的方式进行。两种策略都有其优点和缺点。

我们已经目睹了功能概念的最近兴起,因为它的强项非常吸引人,因为它除其他原因外,还非常适合进行分布式处理。

但是回到OO,您现在可以看到它并不一定要为“现实世界”建模。它的作用是组织程序的行为,以便程序可以展现出满足任何数量的业务目标所需的质量。TDD,DDD和BDD之类的技术是我们发现如何最好地组织对象的方式。诸如“ 原理,模式和实践”“以测试为指导的不断发展的面向对象软件”,“ 示例规范”和“ 域驱动设计 ”等书籍着重介绍了面向对象的理论和实践,重点关注行为驱动设计。

当您读到诸如“观察员,经理,工厂等”之类的信息时,您正在应用OO模式,以帮助您的程序展现某些有用的素质。鉴于您的需求与模式所解决的问题相匹配,它们是“倾向于工作”的“经过验证的收件人”。

我希望这能帮助您理解OO的含义,而又不会在OO和功能范例之间显得过于偏颇。


1

从编程的角度来看,OOP创建了一个不错的模型,它不能反映现实世界。

但是,现实世界有更好的近似值,这是术语领域特定语言(DSL)已知的。例如,Boo使您能够用几乎普通的英语(本文的示例)编写人类可读的代码。

apply_discount_of 5.percent:
         when order.Total > 1000 and customer.IsPreferred
         when order.Total > 10000

suggest_registered_to_preferred:
         when order.Total  > 100 and not customer.IsPreferred

另一个示例是基于Gherkin语言的自动用户接受测试框架。

Feature: Some terse yet descriptive text of what is desired
    In order to realize a named business value
    As an explicit system actor
    I want to gain some beneficial outcome which furthers the goal

Scenario: Some determinable business situation
    Given some precondition
        And some other precondition
    When some action by the actor
        And some other action
        And yet another action
    Then some testable outcome is achieved
        And something else we can check happens too

0

最后由您决定。但是,OOP比其他方法(如结构化或面向过程的编程)是一种精确的方法。循序渐进的技巧可能可以解决您的问题,但是遵循OOP可以使您的生活更轻松。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.