打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
面向对象刨根问底2:OOP竟是从对现实世界的仿真开始的

https://m.toutiao.com/is/L3YcrrN/?=计算机仿真引发面向对象方法的革命 


面向对象现在是流行的编程方法,但你知道OOP竟是从对现实世界的仿真开始的么?让我们仔细研究下历史,弄清楚面向对象方法的来龙去脉,才能从根本上提升软件开发的效率。

Dijkstra(迪科斯彻)对过程式编程的反思

Edsger W. Dijkstra 是著名的计算机科学家和先驱,1972年,他成为第一个既不是美国人也不是英国人获得图灵奖的人。作为计算机科学创始一代最有影响力的人物之一,Dijkstra贡献涵盖了编译器结构、操作系统、分布式系统、顺序和并发编程、编程范例和方法论、编程语言研究。他创造了'结构化编程'这个词,在1970年代,这成为新的编程正统观念。

1965年,Dijkstra写了他著名的《结构化编程笔记》,对新的编程语言产生了深远的影响,特别是Pascal。— Niklaus Wirth, IEEE Annals of the History of Computing (2008)

由Dijkstra的反传统主义引发的编程观革命导致了一场被称为结构化编程的运动,它提倡一种系统,理性的程序构建方法。结构化编程是自编程方法论以来所做的一切的基础,包括面向对象的编程。— Bertrand Meyer, Touch of Class: Learning to Program

Dijkstra(迪科斯彻)是计算机科学的奠基人

Dijkstra得出的结论是,在高级语言中,频繁使用GOTO语句通常是结构不良的症状。Dijkstra认为,在许多高级编程语言中发现的编程语句GOTO是错误的主要来源,因此应该消除。这个观点在编程界引起了巨大的争论。有些人甚至将好的编程等同于GO TO的消除,今天很少有程序员自由地使用它,而且大多数人根本不使用它。

Dijkstra的论点是,如果只允许在有纪律的更高层次结构中,例如if-then-else语句和while循环,则偏离线性控制流会更清晰。这种方法论被发展成结构化编程运动,结构化编程被许多人认为是计算机编程史上的第一次重大运动,在1970年代成为新的编程正统观念。

Dahl(达尔)和 Nygaard(尼加德)

达尔是奥斯陆大学的计算机教授,随着阅历的增加,尤其是ALGOL 60语言使用。他对形式化方法的使用越来越感兴趣,例如严格推理面向对象。他的专长范围从思想的实际应用到其形式数学基础,以确保方法的有效性。

Ole-Johan Dahl是Simula的首席架构师

Nygaard(尼加德)出生于奥斯陆,1956年在奥斯陆大学获得数学硕士学位。他关于抽象概率论的论文题为'蒙特卡罗方法的理论方面'。Nygaard是挪威运筹学会的联合创始人和第一任主席。从尼加德这个身份和作用来看,模拟的数学基础多是出自于他的理论基础。

Nygaard是挪威运筹学学会主席

1960年代,他们一起在挪威计算中心提出了面向对象(OO)编程的最初想法,作为Simula语言的一部分,它最初是ALGOL 60的扩展变体和超集。ALGOL 60是世界上最初的计算机语言之一,几乎你知道的所有计算机语言学的先驱(发明Lisp麦肯锡、发明Fortran的Bacus)都参与到其完善中。达尔和尼加德是第一个发展类、子类(允许隐式信息隐藏)、继承、动态对象创建等概念的人,这些都是OO范式的重要方面。

对象是软件系统中的一个自动包含组件(具有数据结构和相关的过程或方法)。这些组合在一起形成一个完整的系统。面向对象的方法现在在现代软件开发中很普遍,包括广泛使用的命令式编程语言,如C++和Java。

面向对象的编程

Simula 编程语言最初是ALGOL 60的扩展变体和超集,这些语言引入了面向对象编程的核心概念:对象、类、继承、虚拟量和多线程(并行)程序执行。

Simula被认为是第一种面向对象的编程语言,被设计成一种通用编程语言,并为当今面向对象语言的许多功能提供了框架。Simula的影响往往被低估了,Simula类型的对象在C++、ObjectPascal、Java、C#和许多其他语言中被重新实现。 计算机科学家,如C++的创造者Bjarne Stroustrup和Java的创造者James Gosling,已经承认Simula是一个主要的影响。

Nygaard认为需要一种更好的方法来描述系统的异质性和操作。为了进一步了解他对描述系统的正式计算机语言的想法,Nygaard意识到他需要一个比他具有更多计算机编程技能的人。于是,Ole-Johan Dahl加入了他的团队。不久之后,决定将该语言与ALGOL 60联系起来。SIMULA 出生了,一种用于模拟离散事件系统的特殊用途编程语言。

2001年11月,Dahl和Nygaard被电气和电子工程师协会授予IEEE John von Neumann奖章,'以表彰通过设计和实现SIMULA 67引入面向对象编程的基本概念'。2002年4月,他们获得了计算机协会(ACM)颁发的2001年A.M.图灵奖。

离散事件仿真

离散事件仿真(Discrete Event Simulation)系统定义中,“Discrete”表明系统时间上是由离散时间点描述的,比如工作任务发布时间和接受时间,工件开始加工和完成加工的时间点等等。这些时间点在时间轴上是离散。相对来讲,连续系统仿真就是研究连续时间轴上系统的状态变化。“Event”是抽象的事件,就是我们关注的”事”,这些”事”按照一定的规律发生。离散事件仿真就是根据事件在离散的时间点上变化的规律,来描述或者预测系统变化的方法。

随着对制造、交通、网络等人工复杂系统的深入研究,发现随机离散事件是主导这类系统变化和发展的关键,而研究复杂系统常用的微积分工具在其中难以发挥作用,难度在于事件以离散方式发生离散给系统状态的分析带来巨大的难度。

离散事件仿真主要是针对那些系统尚不存在或者难以进行仿真的离散事件进行仿真,以便决策者能够进行更真实的决策。这里举两个例子来说明仿真的必要性。 某银行要在某个地区设置一个营业厅,究竟要租多大面积,设置多少窗口才能满足业务需要呢?面积太大没人来浪费成本,窗口太少顾客排队时间过长满意度下降也不行。这时就要对顾客-业务进行建模,能够估计出顾客总量和业务总量以及分布情况,通过对窗口数量的模拟预估客户的等待时间,得到一个窗口数量的最优值,最终确定营业面积。

从上面的例子可以看出,这些例子中的状态都很难依靠纯粹的数学工具得到令人满意的答案。离散事件仿佛是通过计算帮助决策者进行合理决策的有力工具。在数据驱动业务的今天,对企业业务优化、提高企业运作效率具有举足轻重的作用。

从离散事件仿真的过程来看,分为建模、分析和得到结论几个阶段。为现实世界建模是一个,美国著名统计学家乔治.布克斯曾经说过:“所有模型都是错误的,但一些是有用的”。建立模型需要利用我们先验知识对问题所涉及到的客观世界进行描述,用历史数据去精细化参数和验证;分析是利用计算机的计算能力,对不同策略下,模型未来状态的变化进行推演;得到的结论是根据仿真的结果确定最优策略。

蒙特卡洛方法和排队论

蒙特卡洛方法于20世纪40年代美国在第二次世界大战中研制原子弹的“曼哈顿计划”计划的成员乌拉姆和冯·诺伊曼首先提出。冯·诺伊曼还是世界上第一台计算机的发明者,也是博弈论的奠基人。

他用驰名世界的赌城—摩纳哥的Monte Carlo—来命名这种方法,为它蒙上了一层神秘色彩。蒙特卡罗方法是指当所求解问题是某种随机事件出现的概率,通过某种模拟“实验”的方法,统计这种事件出现的概率。蒙特卡罗法(Monte Carlo method)是以概率和统计的理论、方法为基础的一种计算方法,将所求解的问题同一定的概率模型相联系,用电子计算机实现统计模拟或抽样,以获得问题的近似解,故又称统计模拟法或统计试验法。

排队是我们司空见惯的社会行为,政府大厅、医院、银行、饭店和汽车4S店,排队无处不见,许多组织甚至专门开发了排队叫号系统来保证大家“排好队”。组织在设立之初经常会遇到这样的问题:设立多少个窗口才能保证客户不会发生等待时间过长的现象。虽然我们把排队论放在这里介绍,但排队论本质还是数学模型,并不属于仿真,但排队论的的理论框架是指导离散事件仿真的重要依据。

排队论(queuing theory), 或称随机服务系统理论, 是通过对服务对象到来及服务时间的统计研究,得出这些数量指标(等待时间、排队长度、忙期长短等)的统计规律,然后根据这些规律来改进服务系统的结构或重新组织被服务对象,使得服务系统既能满足服务对象的需要,又能使机构的费用最经济或某些指标最优。

Simula离散事件仿真程序案例

第一看到Simula语言的人可能会大吃一惊,这不是Pascal语言么?老一辈教科书的程序案例都是这样子的。确实如此,Simula语言的Begin End,以及缩进方式影响了很多编程语言。

山姆、莎莉和安迪正在买衣服。他们必须共用一个试衣间。他们每个人都浏览商店约12分钟,然后专门使用试衣间约三分钟,每个人都遵循正态分布。他们的试衣间体验模拟如下:

Simulation Begin Class FittingRoom; Begin Ref (Head) door; Boolean inUse; Procedure request; Begin If inUse Then Begin Wit (door); door.aFirst.Out; End; inUse:= True; End; Procedure leave; Begin inUse:= False; Activate door.First; End; door:- New Head; End; Procedure report (message); Text message; Begin OutFix (Time, 2, 0); OutText (': ' & message); OutImage; End; Process Class Person (pname); Text pname; Begin While True Do Begin Hold (Normal (12, 4, u)); report (pname & ' is requesting the fitting room'); fittingroom1.request; report (pname & ' has entered the fitting room'); Hold (Normal (3, 1, u)); fittingroom1.leave; report (pname & ' has left the fitting room'); End; End; Integer u; Ref (FittingRoom) fittingRoom1; fittingRoom1:- New FittingRoom; Activate New Person ('Sam'); Activate New Person ('Sally'); Activate New Person ('Andy'); Hold (100);End;

主块的前缀是Simulation用于启用仿真。程序包甚至可以嵌套模拟。试衣间对象使用队列 ( door) 来访问试衣间。当有人要求试衣间并且它正在使用时,他们必须在这个队列中等待 ( Wait (door))。当有人离开试衣间时,第一个(如果有)从队列中释放(Activate door.first)并相应地从门队列中移除(door.First.Out)。

Person 是 的子类,Process它的活动使用hold(浏览商店的时间和在试衣间花费的时间)来描述,并调用试衣间对象中的过程来请求和离开试衣间。

主程序创建所有对象并激活所有人员对象以将它们放入事件队列。主程序在程序终止前保持 100 分钟的模拟时间。

为什么是离散事件仿真

大家看到上面离散仿真的程序,可能就明白了,为什么面向对象这个方法会首先诞生在这么一个领域。

首先,离散事件仿真先要对世界事物进行建模。和其他理论有所不同的是,离散事件仿真主要是为了解决运筹学中的问题。这里大部分的对象都分属于几个类别,但是不同的问题是决定了对象的数量不同,甚至程序的目标就是为了求得最优的数量。

在上面的例子中。每一个试衣人都有请求、试衣和离开三个动作。但有多少个人试衣服在问题中是变化的。同样的是试衣间,在这个例子里头只有一个,但是实际上也可以是多个,而每一个试衣间都要有使用中、离开和报告的方法。

排队的例子也是如此。银行需要设一个分行,但希望这个分行客户能够满意。银行首先需要确定这个分行有多少客户和业务,再确定每种业务到来的分布。指标是客户的等待时间,我们发现顾客在等待超过30分钟以后,就会非常不满意。降低对银行的满意度。那我们就把这个30分钟设为界限,然后我们看看到底应该设计多少窗口,使得每个客户等待时间都少于30分钟。

在这个例子中,窗口的数量就是变化的,但每个窗口的性质都是一样的。我们需要动态地去增加减少窗口。实现在窗口数量最小的前提下,还能满足等待不超过30分钟的目标。

所以这种离散事件的模型方式就决定了,如果不用一个类来代表事物中通用的对象,程序组织起来就非常困难。这恐怕也是离散事件仿真领域首先诞生了面向对象的一个原因。

从这个短短的程序里,我们还能看出很多其他的问题,在设计中我们把人员作为过程类的实例,这个面向对象的类别系统并没有跟自然语言的世界完全匹配上,还仅仅是程序员编程思路中的一个方法。

博士聊IT,感兴趣,加关注!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
C和C++的联系与区别
编程语言发展
面向对象是个骗局?!
名家吐槽:面向对象编程从骨子里就有问题
预测未来的最好办法,就是把它创造出来
C++的历史
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服