The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:
有成千上万本关于面向对象编程的书籍,以及数百种面向对象的编程语言。我相信其中大部分(读作“全部”)都给出了一个错误的“对象”定义。这就是为什么整个面向对象编程世界充斥着误解和错误的原因。他们对对象的定义受限于他们所使用的硬件架构,因此非常原始和机械。我想引入一个更好的定义。
那么什么是对象呢?我做了一些研究,这是我找到的内容:
一个对象通过字段存储其状态,并通过方法暴露其行为。
每个对象看起来很像一个小型计算机—它有一个状态,并且有一些可以要求它执行的操作。
一个类是一组保存值的数据字段和对这些值进行操作的方法。
一个对象是保存某种类型值的一些内存。
“一个对象由一些私有的内存和一组操作组成”—Smalltalk-80,Goldberg和Robson,第6页。
所有这些定义中共同的特点是都含有“包含”(或“持有”,“由…组成”,“有”等)这个词。他们都认为对象是一个带有数据的盒子。而这种观点正是我强烈反对的。
如果我们来看看C++或Java是如何实现的,这样对于对象的定义在技术上是正确的。确实,对于每个对象,Java虚拟机在内存中分配了几个字节来存储对象属性。因此,在那种语言中,我们可以在技术上说一个对象是一个带有数据的内存盒子。
没错,但这只是一个特例!
让我们试想一种不将对象属性存储在内存中的另一种面向对象语言。有点困惑吗?请耐心等待一分钟。假设在那种语言中我们定义了一个对象:
在这里,vin
和engine
是对象c
的属性(它是一辆车;现在我们先不考虑类,只关注对象)。因此,有一个简单的对象有两个属性。第一个属性是车辆的VIN,第二个属性是它的发动机。VIN是一个对象v
,而发动机是e
。为了更容易理解,这是一个在Java中类似的对象的样子:
我对JVM不太确定,但是在C++中,这样一个对象在内存中将占用精确的25个字节(假设它是64位x86架构)。前17个字节将被字符数组占用,另外8个字节将被指向具有对象“e”的内存块的指针占用。这就是C++编译器理解对象并将其转换为x86架构的方式。在C++中,对象只是具有明确定义的数据属性分配的数据结构。
在这个例子中,“vin”和“engine”这两个属性是不相等的:“vin”是“数据”,而“engine”是指向另一个对象的“指针”。我故意这样做是为了证明只有“vin”才能将对象称为带有数据的盒子。只有当数据位于对象的“内部”时,我们才能说对象实际上是数据的盒子。对于“engine”来说,这并不完全正确,因为从技术上说,对象内部并没有数据。相反,有一个指向另一个对象的“指针”。如果我们的对象只有一个“engine”属性,它将在内存中占用8个字节,其中没有一个字节实际上被“数据”占用。
现在,让我们回到我们的新伪语言。想象一下,它对待对象与C++非常不同—它根本不将对象属性保留在内存中。它没有指针,也对x86架构一无所知。它只是以某种方式“知道”哪些属性属于一个对象。
因此,在我们的语言中,对象既在技术上又在概念上不再是带有数据的盒子。它们知道数据在哪里,但它们并不“包含”数据。它们“代表”数据,以及其他对象和实体。确实,我们想象语言中的对象“c”代表了另外两个对象:VIN和engine。
总结一下,我们必须明白,尽管一个机械定义的对象在目前市场上大多数编程语言中是正确的,但从概念上讲却是非常不正确的,因为它将对象视为对外部世界过于可见的带有数据的盒子。这种可见性促使我们以过程化的方式思考,并尽可能地访问这些数据。
如果我们将对象视为数据的代表而不是它们的容器,我们就不会想尽快掌握数据。我们会理解数据远在天边,我们不能轻易触碰它们。我们应该与对象进行交流—它如何与数据进行交流不是我们关心的事情。
希望在不久的将来,市场上会引入一些新的面向对象语言,它们不会将对象存储为内存中的数据结构,即使从技术上来说也不会。
顺便说一下,这是我最喜欢的书《对象思考》(作者:大卫·韦斯特)第66页中关于对象的定义:
你认为呢?这是否接近我刚刚提出的“代表性”定义?
Translated by ChatGPT gpt-3.5-turbo/42 on 2023-11-17 at 14:22