龙空技术网

万物皆对象,编程的关键就是找对象

科学圣音 40

前言:

而今兄弟们对“面向对象程序设计及c第二版答案”大概比较看重,咱们都想要分析一些“面向对象程序设计及c第二版答案”的相关资讯。那么小编同时在网上网罗了一些关于“面向对象程序设计及c第二版答案””的相关内容,希望大家能喜欢,看官们一起来了解一下吧!

1

我先问你一个问题,这个世界是由什么构成的?很多人可能马上就会回答,是原子。任何一个真实存在的东西,拆分到最后都是原子。

但是,真的只有原子就可以组成世界吗?我这么问并不是想说原子还可以继续拆分,拆分成电子、质子、中子,毕竟不论是原子,还是电子、质子、中子,都是一种实体,它们和原子只是所处的层级不同。我姑且用原子来统一代表这些真实存在的实体。

只有原子还是远远不够的,如果原子之间不能相互吸引就不能组成分子。原子的种类很少的,加上同位素的话也就几百种,分子的种类就不一样了几乎无穷无尽,所以如果没有分子这个世界的物质将会极其单独的。那样的世界就像是一个巨大的原子沙漠,只有流沙,用流沙是盖不起高楼大厦的。

其实不只是原子、分子,就是我们日常生活中,人、动物、植物、水、空气、阳光等等互相之间也有着各种各样的依赖和互动。

所以,这个世界不只是有实体,还必须有实体之间的相互作用和关系,只有这个世界才能像现在一样存在。

那我再问一个非常哲学的问题,我们这个世界是实体是更重要、更本质呢,还是关系的东西,还是关系更重要呢?

为什么我们讲计算机讲得好好的,忽然开始讨论哲学问题了?别奇怪,这个问题对计算机世界非常重要。

因为,它决定了计算机编程领域里的两大流派。赛博空间里的虚拟世界都是程序员编程实现的,用什么流派的方式来编程,某种程度上这也就决定了赛博空间里的虚拟世界的本质是什么。

甚至,搞明白了这件事,我们都可以回头去想,我们真实的这个世界,本质上到底是实体还是关系。

问题先放在这里,这个问题很大,我估计要用两集的内容好好地讲讲。

2

现在我们还是一点一点地来,上一集我讲了计算机里的实体、实体的状态以及实体的行为动作。你还有印象吧。我举了一个苹果下落的例子,苹果是实体,高度是状态,然后用一个函数来实现苹果下落的过程。

苹果下落总是要落到地面的,这个时候苹果就需要和地面产生关系了,这个过程应该如何实现呢?我们上一集没有讲,这是这一集的任务。

要想明白计算机里面实体如何互相互动,我们需要先考虑一件事,那就是苹果怎么才能感知到地面。也就是说苹果下落的时候,它是怎么知道自己下面有地面,而不是其他东西,而且它还能知道地面有多高,到了这个高度它就不下落了。

这件事在真实世界里面是太自然的事情了,自然到都不会想到这会是一个问题。但是在计算机里面就完全不是这样了。

问题在哪里呢?我们先来看看要想让计算机模拟苹果下落,都需要做什么事情。

主要是两个步骤,第一步是编程把和苹果下落有关的程序全部编写出来,第二步是计算机运行编写好的程序。

你别觉得这很简单啊,魔鬼就隐藏在其中。有什么问题呢?关键在第二步,计算机开始运行编写好的程序之后,程序就会自动运行与程序员无关了,程序员不能干涉正在运行的程序。就是这样,会带来问题。

别急,我们先来回顾一下第一步有关的内容。

在上集讲过,编程的时候,我们需要把真实世界的一个实体投射到赛博空间中,投射过去其实就是一个编号ID,这个编号ID具体是什么数字不重要,它只说明这个东西是在赛博空间里是存在的。分配ID,这是程序员要做的。

如果只是这样的,这个实体还只能算是赛博空间里的一个幽灵,没有大小、没有重量、没有动作、不能和任何其他实体发生作用。

所以,一个投射进来的实体一定是,除了有一个编号ID,还需要把它在真实世界里面可能发生的变化投射到赛博空间里面,也就是一个行为,比如苹果落地。也就是说,程序员还需要一个函数,把苹果落地这个行为编写出来。

一个行为一定是某种状态的改变,所以程序员就需要把具体相关的状态也创造出来。苹果的话,可以是颜色、质量、体积、甜味等等。不只把状态创造出来,还需要给状态附一个具体的数值,哪怕后面你对状态修改了,在创建状态的时候也需要给状态一个初始值。比如,程序员就可以把苹果高度的状态值写进去。

所以程序员编程,或者说把真实世界投射到计算机里面,需要做的事情有3件,分配ID、编写行为函数,创建状态。

多讲一下,行为和状态是无穷无尽的,不需要一次都实现出来,因为在一个程序有里面,比如苹果落地完全不会因为是不是甜而有影响,就可以不投射。

虽然ID、函数、状态的意义不同,但是它们在计算机里全部都是一堆二进制。

这一堆二进制数字,这就是一个在赛博空间里的完整实体了。

第一步完成了,接下来要执行第二步了,让程序运行起来。

这里多介绍一下,一个程序要想运行起来,一定是由另一个程序启动的。比如,你双击点击了桌面上的一个游戏程序,这个游戏就会被操作系统启动。操作系统也是一个程序,它又是由谁启动的呢。它是有一个叫做boot的程序,这个程序不是存在硬盘里的,而是保存在计算机主板的BIOS芯片里面。BIOS又是什么?这个我们就不展开讲了,感兴趣你可以搜索一下。

总之就是boot程序是开机之后运行的第一个程序。如果你去搜索boot,你就知道boot是靴子的意思,在我们现在这个语境下,boot是对bootstraps鞋带的简写。

这是因为在英语里面有一句谚语,"pull oneself up by one's bootstraps",拉着鞋带把自己拉起来。我们都知道这是挺矛盾的事情,其实让计算机启动也是一个矛盾的事情。因为让计算机启动是一个先有鸡还是先有蛋的问题。

让计算机启动起来至少需要让一个程序运行起来,但是要想让一个程序运行起来,必须先要让计算机启动。到底是先有程序还是先启动计算机呢?这就是一个先有鸡还是先有蛋的问题了。

也正是这个原因,所以早期的计算机工程师们就把启动叫做“拉鞋带”,也就是我们刚才说的boot。

这是一个小知识了,我们言归正传。

假如苹果下落这个程序,被操作系统读到了内存里面,并且还执行了苹果下落这个函数。接下来就可以看到计算机屏幕上有一个苹果开始下落了,很快就超出了屏幕下边缘看不到了。虽然看不到了,但是我们可以知道在屏幕的下面,这个苹果会一直下落,因为苹果下落这个函数一直不断地减少苹果高度这个状态。这个状态值越小,苹果的高度越低。

所以,要想苹果可以与地面互动,那就需要让苹果下落这个函数有一个可以停止的功能,不只有停止的功能,这个停止功能还必须与地面有关,当苹果达到地面一样的高度时停止。

问题来了,我前面说了,程序已经运行起来了,程序员无法修改程序了。所以,必须停止苹果下落这个程序运行,修改其中的代码,让地面也加入到程序中。

3

我们再来看一下程序。

我们已经编程,把苹果这个实体创造出来了,它的ID是001,下落这个函数也有了,对应的函数内容可以参照我前面讲过的内容。

然后还需要新增加一个地面实体。地面实体的ID是002。如果想完全复刻它在自然界中的行为,那它的行为可以有很多,比如地震、被水淋湿、长出庄稼等等,但是我们现在考虑的是苹果下落,所以地面不需要有什么动作,也就是动作函数是空。地面这个实体当然也要有状态,这个状态肯定就是地面高度了,有了这个数据,苹果才能知道什么是需要停下来。

现在苹果和地面都有了,接下来就是要让苹果下落这个函数可以知道地面的高度,并且在苹果达到地面高度之后停止运行。

怎么能让苹果下落这个函数知道地面的高度呢?我需要多补充一个小知识,一般编程的时候,只要知道了一个实体的ID,就可以知道它的状态都有哪些,函数都有什么,甚至可以修改状态,让实体执行函数描述的动作。你就可以把实体的ID当做是访问实体所有功能的一个快捷方式。

实际情况肯定要复杂很多,我这是做一个最简单的描述啊。在实际情况里面不是通过ID访问实体的,而是通过把实体赋值个一个变量,通过变量名来进行访问。这就涉及到很多其他知识,我就不细讲了。不本质上是通过ID访问实体是没有区别的。

所以让苹果下落这个函数知道地面高度,就是程序员自己在函数里面直接用地面实体的ID去找到地面高度这个状态。

这样苹果下落这个函数就可以做出如下修改了,这个函数主要进行两个操作,一个是改变苹果高度这个状态,时间越久高度越低,这个和之前一样。还有另一个操作,那就是在修改苹果高度这个状态的同时,还要判断苹果的高度是不是和地面高度一样了,如果一样那么就停止运行。

当然我这里还是最简单的描述,因为一般来说地面的ID是要通过函数的参数传递给函数的,但是这就要牵扯到作用域、局域变量、全局变量这些具体的技术细节里了,我们这里就不细讲了,但是原理上是没有有问题的。

苹果自己本来是不知道地面高度的,但是当运行下落这个函数的时候,程序员就会把地面这个实体ID写在苹果下落的函数里面,这下程序在运行起来之后,不需要程序员干预也能知道地面高度了。

4

但是这种情况还是太特殊了,因为这需要程序员在程序运行前就提前预判,预判出地面一定会在苹果的正下方。

你要知道,程序一旦开始运行起来了,就和程序员无关了,所以要是在程序运行起来之后,苹果正下方的实体改变了,该怎么办呢?

就比如说,这是一个游戏程序的一部分,正常情况下苹果自己会落到地面,但是有的时候也会有这种情况,玩家控制自己的角色走在了苹果树下,苹果落下来并不是落到地面才停止,而是落在玩家角色的手中。

这种情况怎么办呢?在程序员编程的时候无法预测这种情况什么时候出现,不能提前判断是要把地面实体的ID交给苹果下落函数,还是把玩家的ID 交给苹果下落函数。

当然你可能会说,是不是可以把地面这个实体和玩家的实体一起传给苹果落下这个函数。

也可以,这样函数写的时候就需要做3件事了,修改苹果高度值,不只同时判断是不是会碰到玩家的手,还要同时判断是不是会碰到地面。

这其实还是有问题,现在这种情况还是简单,做起来还不麻烦。

可是如果问题变复杂了,比如地面、人、树枝、动物等等所有这些可能出现的意外情况全部考虑进来,那程序员在写苹果下落这个函数的时候,要写的代码就太多了。就算是一只鸟在地球的另一边,只要它理论上有可能在出现在苹果的下面被苹果砸到,那么它就需要被写到苹果下落这个函数里面。是不是想想也觉得挺可怕的。

那怎么办呢?这里问题的关键是,判断什么实体在苹果的下面,这件事是不能省的,就算是地球背面的一只鸟,只要理论上它有可能出现在苹果下面,就需要进行判断。你也可以看出计算机并没有那么智能。

这里其实要减少的是程序员编写代码的工作量,所有的实体都需要判断一遍,但是并不是每一个实体都需要单独写一行代码。

具体怎么做呢?我可以提出一个解决方法。我需要再引入另外一个实体,这个实体很特别,我要把空间看做是一个实体,把真实世界的空间投射到计算机里面。

具体是这样做,首先在程序启动的时候,最先把空间这个实体在计算机里面创造出来。它也有自己的ID,也有自己的状态和行为。

我们先来看空间实体的状态,这个状态比较特别,是一个列表,凡是在空间里的其他实体的ID都保存在这个列表里面。这样做的好处有两个,第一个好处是这样做逻辑上成立,凡是在列表里的我们可以认为它属于这个空间,一个实体属于一个空间这很合理吧。

第二个好处,就是可以通过空间这个列表把所有空间中的实体全部找到,而不需要程序员单独记忆。这样只要通过空间ID,就可以轻松找到所有其他实体了,不论是苹果、地面、树枝、鸟还是玩家。

空间也有自己的行为,这个行为就更特别了,这个行为本身不是真实世界里存在的,而是我创造的,我创造的原因就是为了我自己编程方便。

这个行为函数有一个参数,每当执行的这个函数的时候,都会给这个参数传递一个实体,就比如说给这个行为函数传了一个苹果实体的ID,然后这个函数就会把这个ID正下方的实体ID作为结果进行返回。也就是谁调用这个空间的行为,谁就可以知道自己的正下方是什么实体。

那这个函数怎么做呢?前面讲了,空间的有一个状态是所有其他实体的ID列表,我们需要把每个实体都拿来判断一下,它是不是在苹果的下面。这不是和前面说的情况一样了吗?没省事啊。

不一样了,前面讲的苹果下落函数,程序员需要自己记下来都创建过哪些实体,并且一个实体几行代码一个实体几行代码,这样把所有情况都写下来。如果不是苹果了,而是梨下落,鸭子下落,流星下落,这样的事情还需要再做一遍。

而空间实体的这个行为函数里面就简单了,可以创建一个循环,这个循环每次都会判断一下空间状态的那个列表,看看里面是不是还有实体,如果有就判断这个实体是不是在苹果的下面,然后去看列表里的下一个实体。如此操作,循环往复,直到列表里的所有实体都判断了一遍就可以结束了。

这里的重点是,程序员自己需要编写的代码大幅度减少了,很多工作都交给了程序启动之后再去完成。刚才说的空间行为函数,在程序运行起来之后,不需要程序员干预,自己就可以将所有的实体都找到。这其实就是通过一些巧妙的设计减轻了程序员的工作,只不过这种巧妙的工作并不会减少计算机的工作量。

好,有了空间这个实体之后,其他部分也需要做调整了。首先,所有实体的状态都需要有一个位置坐标,比如经度、纬度和高度,这样空间才能判断其他实体是不是在苹果的正下方。当然,地面特殊一点,它只有高度。

刚才不是说程序运行起来不是第一个创建的是空间这个实体吗?空间创建了之后,再创建其他实体,创建一个就把一个的ID保存到空间的状态中,创建一个保存一个、创建一个保存一个。空间就是一个容器,这样所有创建的实体都能被保存在空间中。除非它不在空间里面。

这是不是还有些盘古开天地的感觉,先开辟出天地这个空间,然后才变出日月星辰、山河湖海。

反过来,所有其他实体也需要增加一个状态,用来保存空间的ID,这样一方面可以证明自己就是在这个空间中。万一是多重宇宙,创造的实体那就有可能在别的空间里了。

另一方面,也是更重要的是可以方便地调用空间的那个行为函数,有了ID就能找到对应实体的一切。

这样苹果下落的函数就可以这么来写了,在苹果下落的函数里面,先找到空间的ID,通过ID调用空间的行为函数,也就是判断苹果的下面有什么实体。空间的这个函数执行完了之后会产生一个结果,这个结果就是苹果正下面的那个实体的ID,把ID保存下来。

执行到这里,我先你也应该知道怎么做了,一边减少自己高度的状态,一边判断自己的高度是不是和那个正下方的实体高度一样,如果一样停止下落。

至此,所有问题全部搞定。我也给你展示了一个经过简化,但是比较完整的过程,如何编程,将真实世界投射到计算机中。

你也看到了,在这个过程中,一切都与ID、状态和行为函数有关,而这3个东西有是依赖于实体这个概念上的,它们是实体这个概念的子集,这3个东西组合在一起才是一个实体。实体就是这个编程过程的核心。

5

其实,这个思想在编程中是非常重要的,也不是我原创的。我其实是“抄袭”了面向对象思想,就是那个大名鼎鼎的面向对象编。我前面说的实体,在面向对象的思想里其实就是一个一个的对象。对象,也都有自己的状态和行为。

在面向对象语言中有一句名言,叫做“万物皆对象”,就是说,你可以把世界万事万物都可以看做是一个一个的对象,只要把这些对象重建出来,实现好它们的状态和行为,那么在计算机世界里面创建一个新世界也不是不可能的。大白话说,对象、状态、行为,就是面向对象编程的基本套路。

现在市面上主流的编程软件都支持面向对象的,像是C++,Java,Python它们甚至都是以面向对象为基础的编程语言。

当然,我讲的这些还是面向对象的一个最简单的介绍,面向对象的思想可是非常深刻的,其中还有类与对象的关系啊,类之间的继承关系啊,封装问题啊等等,如果你想要学习一个编程语言这些概念一定是会遇到的。现在就不细讲了,以后有机会了再详细介绍,这些内容也非常有意思。

你可能还听过C语言,最经典的高级编程语言,为什么前面讲的那些编程语言里面没有C语言呢?

这是因为C语言并不是面向对象的,按照专业的说法,C语言是面向过程的编程语言。

你不用理解面向过程是什么意思,其实它对世界的理解与面向对象并没有什么本质区别,也都是用一个数字编号表示事物是否存在,用数字表示状态,用函数表示关系,只不过在把没有面向对象思考和建模的方便工具。如果你感兴趣,我们以后还会介绍这它们两个之间的关系。

6

现在,我最想强调还有一点,不知道你注意到没有,刚才我把苹果当做是一个实体投射到计算机空间里面,其实并不是一个理所当然的事情。你可能会说,苹果是一个实体,这还不显而易见吗?难道还能出什么幺蛾子?

那我就要问你了,苹果是不是有各种分子构成的,理论上我们是不是应该把这些分子看做实体,苹果只是这些分子的集合。还有苹果和地面的碰撞,本质上也不是苹果落地就不动了,而是苹果分子和地面分子之间发生了发生了电磁作用,如果写函数更严谨的方法是不是应该电磁方程写到函数里面呢?

你可能会说,一个苹果落地问题,还要牵扯到分子构成、电磁作用,是不是太小题大做了,没有必要啊。

没错,就是没有必要,我们当前这个问题直接把苹果当做一个实体是为了简单、方便做出的简化,可以说是在更简单实现还是更真实还原世界,这两者之间做出了取舍,选择了更简单实现。

所以,为什么说程序员编程其实是一种艺术创造,它和盖房子修铁路并不一样,那些工作几乎只需要按步骤把工作完成。而编程就不是了,这个世界有哪些实体、有哪些状态、有哪些实体并不是一眼就可以看出来了,程序员需要根据自己的需求和经验,创造性地对真实世界进行划分,再投射到赛博空间里面。

就比如前面提到的,我作为一个程序员,考虑苹果下落问题是,就不只考虑落到地面,还考虑苹果会落到其他东西上面,而且我的解决方案也不显而易见,是把空间也看做是一个对象,所有在空间里的东西都可以通过空间找到。

如果没有把空间看做对象可不可以呢?当然可以,但是这也做出来的程序更麻烦,不灵活,万一有什么改动需要修改大量的代码。那有没有比我这个主意更好的方法呢,肯定也是有的。

所以,编程是什么?不只是写代码,还需要设计出对世界的划分方法。其实设计划分世界的方法,是应该把这部分看做一个实体呢,还是把另外一部分看做实体呢,这并没显而易见,也没有标准答案。同一个实体,它的状态和行为又有哪些,也没有标准答案。

我们也可以把这个过程叫做建立模型,当然,建模的概念是非常广的,此时此刻你可以把建立模型理解成构建实体、构建实体中状态和行为的过程。一个优秀的程序员最核心的能力并不是写出来的代码是不是运行得更快,是不是只需要用更少的代码,而是建立的模型是不是适合当前的问题,是不是可以更容易实现,更容易修改。

你可能也听过,一个优秀的程序员要有非常强的抽象能力和数学能力,这个抽象能力和数学能力是什么,就是面对真实的世界、面对真实的问题,能不能建立模型,建立的模型是不是简单方便。

以前听的建模,你可能还不知道是干什么,现在你应该知道了,程序员说的建模,就是让你考虑需要把什么当做对象,考虑对象里需要有哪些状态,又需要有哪些行为,考虑如何让这些对象能在赛博空间中像你希望的那样运行。

刚才不是说过“万物皆对象”吗,那么程序员建模,我们就能说是程序员在“找对象”。。。

我刚才这么一顿讲,我要带你回到最前面的问题了,我们这个世界到底是有什么构成?是实体吗?还是关系呢?

我们不是上帝,可能没有办法一下子给出答案,但是我可以假设自己是上帝,计算机就是创造新世界的工具。要想在计算机的赛博空间里面创造一个世界是不是需要编程啊,那编程是不是需要用到面向对象的思想啊。面向对象是什么,那就是万物皆对象啊,对象就是对实体的抽象,那我们创造一个世界的话,那是不是就可以说这个世界的本质是实体呢?

既然这样的话,那我们是不是完全可以假设上帝就是一个特别牛的程序员,他用面向对象的方法创造了我们的世界呢?

刚才讲的逻辑清晰、思路顺畅,应该就是这样了吧。

标签: #面向对象程序设计及c第二版答案