程序设计方案方法的演化及极限Word格式文档下载.docx
《程序设计方案方法的演化及极限Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《程序设计方案方法的演化及极限Word格式文档下载.docx(21页珍藏版)》请在冰点文库上搜索。
与其说程序设计是一项工作,倒不如说它是程序员的个人技艺。
但是,随着大容量存储器的出现及计算机技术的广泛应用,程序编写越来越困难,程序的大小以算术基数递增,而程序的逻辑控制难度则以几何基数递增,人们不得不考虑程序设计的方法。
最早提出的方法是结构化程序设计方法,其核心是模块化。
1968年Dijskstra在计算机通讯上发表文章[1],注意到了“结构化程序设计”,之后,Wulf主张“可以没有GOTO语句”[2]。
至1975年起,许多学者研究了“把非结构化程序转化为结构化程序的方法”,“非结构的种类及其转化”,“结构化与非结构化的概念”,“流程图的分解理论”等问题。
结构化程序设计逐步形成既有理论指导又有切实可行方法的一门独立学科。
SP方法主张使用顺序、选择、循环三种基本结构来嵌套连结成具有复杂层次的“结构化程序”,严格控制GOTO语句的使用。
用这样的方法编出的程序在结构上具有以下效果:
(1>
以控制结构为单位,只有一个入口,一个出口,所以能独立地理解这一部分。
(2>
能够以控制结构为单位,从上到下顺序地阅读程序文本。
(3>
由于程序的静态描述与执行时的控制流程容易对应,所以能够方便正确地理解程序的动作。
SP的要点是:
“自顶而下,逐步求精”的设计思想,“独立功能,单出入口”的模块仅用3种(顺序、分支、循环>
基本控制结构的编码原则[3]。
自顶而下的出发点是从问题的总体目标开始,抽象低层的细节,先专心构造高层的结构,然后再一层一层地分解和细化。
这使设计者能把握主题,高屋建瓴,避免一开始就陷入复杂的细节中,使复杂的设计过程变得简单明了,过程的结果也容易做到正确可靠。
独立功能,单出、入口的模块结构减少了模块的相互联系使模块可作为插件或积木使用,降低程序的复杂性,提高可靠性。
程序编写时,所有模块的功能通过相应的子程序(函数或过程>
的代码来实现。
程序的主体是子程序层次库,它与功能模块的抽象层次相对应,编码原则使得程序流程简洁、清晰,增强可读性。
在SP中,划分模块不能随心所欲地把整个程序简单地分解成一个个程序段,而必须按照一定的方法进行。
模块的根本特征是“相对独立,功能单一”。
换言之,一个好的模块必须具有高度的独立性和相对较强的功能。
模块的好坏,通常用“耦合度”和“内聚度”两个指标从不同侧面而加以度量。
所谓耦合度,是指模块之间相互依赖性大小的度量,耦合度越小,模块的相对独立性越大。
所谓内聚度,是指模块内各成份之间相互依赖性大小的度量,内聚度越大,模块各成份之间联系越紧密,其功能越强。
因此在模块划分应当做到“耦合度尽量小,内聚度尽量大”。
结构化程序相比于非结构化程序有较好的可靠、易验证性和可修改性;
结构化设计方法的设计思想清晰,符合人们处理问题的习惯,易学易用,模块层次分明,便于分工开发和调试,程序可读性强。
其设计语言以Ada语言为代表。
3.面向对象程序设计
20世纪90年代,由于计算机硬件的飞速发展,对软件系统在规模和性能方面的要求也在不断的提高。
因此,传统的程序设计方法使得软件和硬件能力的差距迅速扩大。
传统的软件工具、软件技术和抽象层次越来越难以适应大规模复杂软件系统的开发特点。
因此,软件能力已成为制约软件发展的主要因素。
OOP方法源于20世纪70年代中后期,在20世纪80年代逐步代替了传统的SP方法,成为最重要的方法之一,至今OOP方法被广泛应用于各个领域。
面向对象的基本思想与结构化设计思想完全不同,面向对象的方法学认为世界由各种对象组成,任何事物都是对象,是某个对象类的实例,复杂的对象可由较简单的对象的某种方式组成。
OOP的基石是对象和类。
对象是数据及对这些数据施加的操作结合在一起所构成的独立实体的总称;
类是一组具有相同数据结构和相同操作的对象的描述。
面向对象的基本机制是方法和消息,消息是要求某个对象执行类中某个操作的规格说明;
方法是对象所能执行的操作,它是类中所定义的函数,描述对象执行某个操作的算法,每一个对象类都定义了一组方法。
OOP有3个重要特性:
封装性、继承性和多态性。
封装性是指对象是数据和处理该数据的方法所构成的整体,外界只能看到其外部特性(消息模式、处理能力等>
,其内特性(私有数据、处理方法等>
对外不可见。
对象的封装性使得信息具有隐蔽性,它减少了程序成分间的相互依赖,降低程序的复杂性,提高程序的可靠性和数据的安全性。
继承性(Inheritance>
反映的是类与类之间的不同抽象级别,根据继承与被继承的关系,可分为基类和衍生类,基类也称为父类,衍生类也称为子类,正如“继承”这个词给我们的字面提示一样,子类从父类那里获得所有的属性和方法,并且可以对这些获得的属性和方法加以改造,使之具有自己的特点。
继承性使得相似的对象可以共享程序代码和数据,继承性是程序可重用性的关键。
多态性是指在形式上表现为一个方法根据传递给它的参数的不同,可以调用不同的方法体,实现不同的操作。
将多态性映射到现实世界中,则表现为同一个事物随着环境的不同,可以有不同的表现形态及不同的和其他事物通信的方式。
多态性使程序员能在一个类等级中使用相同函数的多个版本,程序员可以集中精力开发可重用的类和方法而不必过分担心名字的冲突问题。
OOP方法是以“对象”为中心进行分析和设计,紧抓“模型化世界”的对象,使这些对象形成了解决目标问题的基本构件,即解决从“用什么做”到“要做什么”。
其解决过程从总体上说是采用自底向上方法,先将问题空间划分为一系列对象的集合,再将对象集合进行分类抽象,一些具有相同属性行为的对象被抽象为一个类,类还可抽象分为子类、超类(超类是子类的抽象>
。
其间采用继承来建立这些类之间的联系,形成结构层次。
同时对于每个具体类的内部结构,又可采用自顶向下逐步细化的方法由粗到细精化之。
调试运行时通过向类对象发消息来完成,对象执行相应操作并返回结果,使对象集的初始状态变成了终态。
故OOP总体来说主要是不断设计新的类和创建对象的过程。
与传统的SP相比,OOP方法具有许多优点,如采用“对象”为中心的设计方式,再现了人类认识事物的思维方式和解决问题的工作方式;
OOP方法以对象为唯一的语义模型,整个软件任务是通过各对象(类>
之间相互传递消息的手段协同完成。
因此,能尽量逼真地模拟客观世界及其事物;
由对象和类实现了模块化,类继承实现了抽象对象,以及任一对象的内部状态和功能的实现的细节对外都是不可见的,因此很好地实现信息隐藏。
由此建立在类及其继承性基础上的重用能力可应付复杂的大型的软件开发。
面向对象方法使得软件具有良好的体系结构、便于软件构件化、软件复用和良好的扩展性和维护性,抽象程度高,因而具有较高的生产效率。
目前,面向对象程序设计语言以Java、C++
为代表。
4.后面向对象方法
虽然面向对象程序设计方法有诸多优点,但经过多年的实践摸索,人们也发现面向对象方法有其不足,如许多软件系统不完全都能按系统的功能来划分构件,
仍然有许多重要的需求和设计决策,比如安全、日志等,它们具有一种“贯穿特性”<
crosscutting
concerns),无论是采用面向对象语言还是过程型语言,都难以用清晰的、模块化的代码实现。
最后的结果经常是:
实现这些设计决策的代码分布贯穿于整个系统的基本功能代码中,形成了常见的“代码散布”(code
scattering>
和“代码交织”(code
tangling>
现象。
代码交织现象是现有软件系统中许多不必要的复杂性的核心。
它增加了功能构件之间的依赖性,分散了构件原来假定要做的事情,提供了许多程序设计出错的机会,使得一些功能构件难以复用,源代码难以开发、理解和发展。
因此,人们在面向对象的基础上发展了更多的新技术,借以弥补面向对象技术的缺陷,使得面向对象技术能够更好的解决软件开发中的问题。
这些建立在面向对象的基础上、并对面向对象做出扩展的新技术被广泛应用的时期,我们把它称为“后面向对象时代”。
在后面向对象时代,有许多新型的程序设计思想值得关注。
4.1
面向方面程序设计
面向方面程序设计(Aspect-Oriented
programming,
AOP>
方法,这一概念最早是由施乐(Xerox>
公司在美国加州硅谷PaloAlto
研究中心<
PARC)的首席科学家、加拿大大不列颠哥伦比亚大学教授Gregor
Kicgales
等人首次在1997
年的欧洲面向对象编程大会(ECOOP
97>
上提出[4]。
所谓的Aspect,就是AOP提供的一种程序设计单元,它可以将上文提到的那些在传统程序设计方法学中难于清晰地封装并模块化实现的设计决策,封装实现为独立的模块。
Aspect是AOP的核心,它超越了子程序和继承,是AOP将贯穿特性局部化和模块化的实现机制。
通过将贯穿特性集中到Aspect中,AOP就取得一种单一的结构化行为---该行为在传统程序中分布于整个代码中--这样就使Aspect代码和系统目标都易于理解。
在AOP中,Aspect是AOP中的一阶实体,AOP中的Aspect正如OOP中的类。
现有对Aspect的认识有错误校验策略、设计模式、同步策略、资源共享、分布关系和性能优化等。
Aspect的实现和传统开法方法中模块的实现不同。
Aspect之间是一种松耦合的关系,各Aspect的开发彼此独立。
主代码的开发者甚至可能没有意识到Aspect的存在,只是在最后系统组装时刻,才将各Aspect代码和主代码编排融合在一起。
因此,主代码和Aspect之间可以是一种不同于传统“显式调用”关系的“隐式调用”[5]。
在软件复杂性日益增加的今天,隐式调用有巨大的优点,因为某一应用的领域专家,不太可能对分布、认证、访问控制、同步、加密、冗余等问题的复杂的实现机制很熟悉,因此就不能保证他们在程序中进行正确的调用。
在当前强调程序演化的情况下,这一点尤其重要,因为开发人员很难正确预见到未来对程序的新需求。
AOP
是一种关注点分离技术,通过运用aspect
这种程序设计单元,允许开发者使用结构化的设计和代码,反映其对系统的认识方式。
要使设计和代码更加模块化、更具结构化,使关注点局部化而不是分散于整个系统中。
同时,需使关注点和系统其他部分保持良好定义的接口,从而真正达到“分离关注点,分而治之”的目的。
有关AOP更加详细的资料,读者可以进入希赛网<
)的“技术应用”频道中的“IT新技术”栏目,阅读相关的文章。
4.2
面向Agent程序设计
随着软件系统服务能力要求的不断提高,在系统中引入智能因素已经成为必然。
Agent作为人工智能研究重要而先进的分支,引起了科学、工程、技术界的高度重视。
斯坦福大学的Barbara
Hayes-Roth在IJCAI’95的特约报告中提及:
智能的计算机主体既是人工智能最初的目标,也是人工智能最终的目标。
在计算机科学主流中,Agent的概念作为一个自包含、并行执行的软件过程能够封装一些状态并通过传递消息与其它Agent进行通信,被看作是面向对象程序设计的一个自然发展。
Agent具有以下主要特征:
代理性(Action
On
Behalf
Others>
代理具有代表他人的能力,即它们都代表用户工作。
这是代理的第一特征。
自制性(Autonomy>
一个代理是一个独立的计算实体,具有不同程度的自制能力。
它能在非事先规划、动态的环境中解决实际问题,在没有用户参与的情况下,独立发现和索取符合拥护需要的资源、服务等等。
主动性(Proactivity>
代理能够遵循承诺采取主动,表现面向目标的行为。
例如,Internet上的代理可以漫游全网,为用户收集信息,并将信息提交给用户。
(4>
反应性(Reactivity>
代理能感知环境,并对环境作出适当的反应。
(5>
社会性(Social
Ability>
代理具有一定的社会性,即它们可能同代理代表的用户、资源、其它代理进行交流。
(6>
智能性(Intelligence>
代理具有一定程度的智能,包括推理到自学习等一系列的智能行为
(7>
移动性(Mobility>
代理具有移动的能力,为完成任务,可以从一个节点移动到另一个节点。
比如访问远程资源、转移到环境适合的节点进行工作等。
面向Agent的程序设计(Agent-Oriented
programming>
方法与面向对象程序设计方法的最基本区别在于Agent的社会性。
面向Agent程序设计的主要思想是:
根据Agent理论所题推出的代表性Agent特性的、精神的和有意识的概念直接设计Agent。
这样一个目的后面的动机是人们运用意愿姿态作为一个代表复杂系统的抽象机制。
由于Agent的上述特性,基于Agent的系统应是一个集灵活性、智能性、可扩展性、稳定性、组织性等诸多优点于一身的高级系统。
4.3
其它后面向对象程序设计
除了上述两种主流的后面向对象程序设计方法外,还出现了许多值得关注的新的程序设计方法。
如:
<
1)泛型程序设计(generic
Programming,GP>
GP是一种范型(paradigm>
它致力于将各种类型按照一小组功能性的需求加以抽象,然后以这些需求为条件实现算法。
由于算法在其操作的数据类型上定义了一个严格的窄接口,同一个算法便可以应用于各种类型之上。
GP为应用程序开发人员提出了十分美妙的承诺。
它使“从‘一种一个’的软件系统向自动制作软件的各不相同的变体发展”这种思路变得十分真实可信。
简单地说,GP以“确定软件开发中自动化的好处”为中心进行软件开发。
2)面向构件程序设计。
在面向构件程序设计中构件就是一组业务功能的规格,面向构件针对的是业务规格,不需要源代码,可执行代码或者中间层的编译代码,在这个层面上可以做到代码的集成、封装、多态,做到AOP,这才是面向构件的精髓。
面向构件技术还包括了另一个重要思想,这就是程序在动态运行时构件的自动装载。
3)敏捷方法(Agile
Methodologies>
敏捷也称作轻量级开发方法,
对许多人来说,这类方法的吸引之处在于对繁文缛节的官僚过程的反叛。
它们在无过程和过于繁琐的过程中达到了一种平衡,使得能以不多的步骤过程获取较满意的结果。
敏捷型方法强调“适应性”而非“预见性”,敏捷型方法变化的目的就是成为适应变化的过程,甚至能允许改变自身来适应变化。
敏捷型方法是“面向人”的(people-oriented>
而非“面向过程”的
(process-oriented>
,敏捷型方法认为没有任何过程能代替开发组的技能,过程起的作用是对开发组的工作提供支持。
5.程序设计方法的极限
软件工程发展的一个侧重方向是对软件开发过程中分析、设计的方法的研究。
这方面的第一个重要成果就是在70年代风靡一时的结构化开发方法,即PO(面向过程的开发或结构话方法>
PO是人们在用计算机世界来表达现实世界时,追求过程话、模块化、封装以及更高的抽象的结果。
人们用计算机来映射现实世界时,最低层的实现无非是靠数字电路技术产生的高电平与低电平信号。
在PO中,人们关注的是如何用函数和过程来实现对现实世界的模拟,将其映射到计算机世界之中。
OO是这种抽象层次不断提高的过程的自然发展结果,它采用类和对象的概念,把变量以及对变量进行操作的函数和过程封装在一起,用这种更高一级的抽象来表达客观世界。
通常,一个对象包含一些属性和方法,它对应于自然语言中一个有意义的名词,描述了现实世界中的一个物体(物理实体>
或概念(抽象实体>
我们知道,软件工程的发展历史就是人们不断追求更高的抽象、封装和模块化的历史。
OO当然不会是历史的终结。
尽管不能精确得到OO之后是什么,我们至少可以推知,OO之后的XO,必然将是比OO更高一级的抽象。
它所依赖的核心概念必然高于并包容对象这一概念。
正如对象高于并包容了函数和变量一样。
OO之后是什么呢?
可能是FO--Function
Oriented<
面向泛函)。
这里的Function不同于我们在当前编程所用的函数Function,这里的Function指职能模块高级抽象。
所谓职能模块,是指可独立完成特定任务,而对无力完成的任务可自行找到具备完成该任务功能的其它职能模块,并与之建立联系以合力完成工作的功能体。
FO
需要高速智能网络、智能接口、分布式技术、并行技术,最重要的是需要一个国际化的管理机构。
假如,OO之后是FO,那么我们当然要问FO之后会是什么呢?
再往下又会是什么,有没有一个极限呢?
如果有极限是什么呢?
如果从计算机和数学理论回答这个问题是很困难的,但是,我们换个角度,以哲学的观点来分析这个问题。
现实世界中的任何事物都有其发生、发展、成熟和灭亡的过程,假如把程序设计方法是一个事物,那么它也应该有其发生、发展、成熟和灭亡的经历。
正如最初是不存在程序设计方法这个概念,随着计算机硬件的发展,出现了SP方法,紧接着就是OOP方法,到后OOP时代…,程序设计方法也遵循着这样一个自然规律。
也就是说,程序设计方法肯定是有其极限的,可能若干年后我们所需要的不在是程序设计方法这样一个概念了,而是在更抽象的层次上智能的生产软件。
现在让我们假设软件工程已经发展到了这样一个理想的境界,有一天我们实现了自然语言编程,是否就万事大吉了?
换句话,自然语言是否能很好地描述、表达客观感知世界?
维特根斯坦在《逻辑哲学论》里已经指出:
世界的意义必定存在于世界之外;
实际上存在着不可表达的东西;
这显示了它的存在,它是神秘的;
也就是说,外部世界中存在一些我们可以感知却无法用语言来表达的东西;
“对于那些不可言说的,必须保持沉默”这句话,成为我们最后的极限。
论程序设计方法
如果你是初学者----------------请不要阅读;
但有志成为中高级程序员--------请务必阅读;
如果你是中级程序员------------请务必阅读;
如果你高级程序员--------------请批评指正。
本文是我在“软件工程师班”开学第一节课的讲义,和“计算机软件设计发展”讲座上的内容整理而成。
写作本文的目的是引导学生从更高的层次来看待程序设计方法,为将来成为高级程序员而做好理论准备。
一、计算机硬件环境对软件设计方法的限制
计算机的发明到现在已经60年了,计算机程序设计方法也伴随着计算机硬件技术的提高而不断发展。
硬件环境对软件设计既有严重的制约作用,也有积极的推动作用。
在我的大学母校<
此处删除6个字),数学系的一些老师,有幸成为了我国第一代的计算机DIY一族。
呵呵,不要以为是组装PC机呦,他们组装的可是小型机。
一人多高铁皮柜大小的主机,加上纸带机<
后期改进为读卡机),组装好后,除了供学校自己的科研使用外,还在全国各地销售了十几台。
当时<
七十年代)一台的售价是10几万元人民币,如果换算到今天,相当于价值大约为100多万元,非常高档的小型计算机了。
下面大家猜猜,这么高档的计算机,它的内存是多少那?
<
都把嘴闭好了,我要公布答案了)——4K。
一块50公分见方的内存板,
插入到主机箱中,好了------1K;
再插一块内存板,好了------2K;
再插一块内存板,好了------3K;
再插一块内存板,好了------4K;
再......不行了,插不起了,太贵了!
这就是当时的环境。
这样的环境下,用什么写程序那?
当然只有机器码了。
先用汇编写,然后翻阅手册手工改写为机器码,然后打卡或穿纸带,输入运行。
可以想象,在当时的条件下,什么叫好的程序那?
什么叫优秀的程序那?
——技巧!
程序设计的最初始阶段,是讲究技巧的年代。
如何能节省一个字节,如何能提高程序运行的效率,这些都是要严肃考虑的问题。
而所谓的程序的易读性,程序的可维护性根本不在考虑范围之内。
今天,35岁以上的学习过计算机的朋友可能都使用过一种个人计算机——APPLE-II<
中国也生产过这种计算机的类似产品“中华学习机”)。
主频1M,内存48K<
扩展后,最多可达到64K)。
我就是使用这样的计算机长大的:
>
当年,类似的个人计算机产品,还有PC1500,Layser310等。
这种计算机上已经固化了BASIC语言,当然只是为学习使用。
要想开发出真正的商业程序,则必须使用汇编,否则的话,程序就比蜗牛还要慢了。
于是,程序设计中对于技巧的运用,是至关重要的了。
题外话1:
比尔盖茨是BASIC的忠实拥护和推动者。
当年,他在没有调式环境的状况下,用汇编语言写出了一款仅有4K大小的BASIC解释器,且一次通过。
确实令人佩服。
不象现在微软出品的程序,动辄几十兆。
)这也许就是比尔对BASIC情有独钟的原因,每当微软推出<
临摹)一个新技术,则他会立刻在BASIC中提供支持。
题外话2:
在APPLE-II上有一款游戏软件“警察抓小偷”,当年熬夜玩游戏,乐趣无穷。
后来这款游戏被移植到了PC上,咳~~~根本没有办法玩,因为小偷还没跑就被警察抓到了。
硬件的速度提升,另我无法再回味以前的时光了。
二、结构化程序设计
随着计算机的价格不断下降,硬件环境不断改善,运行速度不断提升。
程序越写越大,功能越来越强,讲究技巧的程序设计方法已经不能适应需求了。
记得是哪本书上讲过,一个软件的开发成本是由:
程序设计30%和程序维护70%构成。
这是书上给出的一个理论值,但实际上,从我十几年的工作经验中,我得到的体会是:
程序设计占10%,而维护要占90%。
也许我说的还是太保守了,维护的成本还应该再提