1.JAVA 编程思想——对象入门

欢迎转载,转载请标明出处:    http://blog.csdn.net/notbaron/article/details/51040219  
 如果学JAVA,没有读透《JAVA 编程思想》这本书,实在不好意思和别人说自己学过JAVA。鉴于此,蛤蟆忙里偷闲,偷偷翻看这本传说中的牛书。
面向对象编程OOP具有多方面吸引力。实现了更快和更廉价的开发与维护过程。对分析与设计人员,建模处理变得更加简单,能生成清晰、已于维护的设计方案。
       这些描述看上去非常吸引人的,不过蛤蟆还是没啥印象(至少到现在为止)。
       任何事情都有两面性,坏的一面是什么?要享受这么好的待遇,当然需要付出更大的努力了,要抛去之前的程序化思维,采用形象思维。而且对象的设计过程更具挑战性,特别是创建可重复使用的对象时。
       关于坏处的最后一点,设计的挑战性,不用太担心。我们大多数人在很多情况下根本不需要去设计自己的对象的,可以利用现有的专家已经设计出来的对象来解决自己的应用问题,这点很重要。我们要站在巨人的肩膀上,而不是去重复发明轮子,对不对?毕竟人生短暂,一晃而过。不过话说回来,如果在某一天需要的时候我们还是需要回头看看,是站在了谁的肩膀上以及轮子发明的过程,这个思想发展的过程对个人修养以及智慧的积累是大有裨益的。
       
1      关于抽象
有人说,编程语言的最终目的都是提供一种抽象方法。
       汇编语言是对基础机器的抽象;FORTRAN和C是对汇编的抽象。
       LISP和APL将所有问题归纳我i算法,PROLOG将所有问题都归纳为决策链。它们都有自己一套解决某一个问题的杀手锏,但是只要超过了力所能及的范围就会显得笨拙。
       面向对象在之前的程序设计集成商,又跨出了一步。将问题空间中的元素以及在方案空间的表示物称为”对象”(Object).(小伙伴们如果是程序员,那么就狠狠亲下它吧,也许这辈子你就离不开它了。)通过添加新的对象类型,可进行灵活的调整,以便与特定的问题配合。OOP根据问题来描述问题,而不是根据方案,与现实世界的对象相比,也存在共通的地方:都有自己的特征和行为。
       JAVA还有个爹,叫做SmallTalk. 它爹也是Alan Kay发明的。那我们来看看JAVA它爹的创始人对于面向对象程序设计方法的总结:
l  所有东西都是对象。可将对象想象成一种新型变量;它保存着数据,但可要求它对自身进行操作。理论上讲,可从要解决的问题身上提出所有概念性的组件,然后在程序中将其表达为一个对象。
l  程序是一大堆对象的组合;通过消息传递,各对象知道自己该做些什么。为了向对象发出请求,需向那个对象“发送一条消息”。更具体地讲,可将消息想象为一个调用请求,它调用的是从属于目标对象的一个子例程或函数。
l  每个对象都有自己的存储空间,可容纳其他对象。或者说,通过封装现有对象,可制作出新型对象。所以,尽管对象的概念非常简单,但在程序中却可达到任意高的复杂程度。
l  每个对象都有一种类型。根据语法,每个对象都是某个“类”的一个“实例”。其中,“类”(Class)是“类型”(Type)的同义词。一个类最重要的特征就是“能将什么消息发给它?”。
l  同一类所有对象都能接收相同的消息。这实际是别有含义的一种说法,大家不久便能理解。由于类型为“圆”(Circle)的一个对象也属于类型为“形状”(Shape)的一个对象,所以一个圆完全能接收形状消息。这意味着可让程序代码统一指挥“形状”,令其自动控制所有符合“形状”描述的对象,其中自然包括“圆”。这一特性称为对象的“可替换性”,是OOP最重要的概念之一。
5大特征,总结成一句话就是:所有东西都是对象,程序是对象的组合,对象有自己的存储空间和一种类型,同一类对象都能接受相同的消息。
       
2      关于对象的接口
类具有自己的通用特征与行为。每个对象都隶属于一个特定的类。
       类建好后,根据情况生成许多对象。将对象作为解决问题中存在的元素进行处理。此处会碰到面向对象程序设计的一大挑战,如何在问题实际存在的地方与实际问题进行建模的地方建立理想的一对一对应或映射关系。
       我们向对象发出的请求是通过它的接口定义的,对象的类型或类 则规定了它的接口形式。类型与接口的等价或对应关系是面向对象程序设计的基础。
       例如灯这个类型:

       接口规定了可对一个特定的对象发出哪些请求。但是在某个地方存在一些代码以满足实现,这代码与隐藏起来的数据佳作隐藏的实现。向对象发送一条消息,对象决定如何对这条消息作出反应。
       有两个原因需要控制对成员的访问。1、防止程序员接触不该接触的东西,用户操作接口即可,不需明白这些信息。2、允许库设计人员修改内部接口,而不会对调用者造成影响。
       JAVA有三个显示关键字和一个隐式关键字来设置类边界:public,private,protected以及friendly。“pulibc” 意味着后续的定义任何人均可使用。”private”除了自己、类型的创建者以及那个类型的内部函数成员,其他任何人都不能访问后续的定义信息。
3      关于方案的重复使用
蛤蟆你在干嘛?
编程思想的笔记啊~~~好吧,继续
创建并测试好一个类后,那么就是一个有用的代码单位了。但是这样重复的方案并不容易。我们先不管这个设计上的问题吧。
有了一个类,新类就可由任意数量和类型的其他对象构成。这个叫做组织了。也成包含关系,就像一辆车包含一个发动机那样了。
 
4      关于继承
如果做出一个新的数据类型后,又逼着你实现一个功能大致相同的数据结构,你会不会疯?所以就需要继承了,就是针对这个目标而设计的。
继承的类与基础类有相同的类型,有相同的接口。当然根据需要可以给继承类添加函数什么的。
4.1      改善基础类
JAVA中有extends关键字,暗示我们要为接口“扩展”新功能。为区分新类,需要改变原先的函数,尽管使用的函数接口未变,但它的新版本具有不同的表现。
4.2      等价于类似关系
继承类只能改善原基础类的函数?如实只能改善,那么就说继承类和基础类是完全相同类型的接口。那么基础类和继承类就存在一种等价关系了。如果圆继承与几何形状,那么“圆就是一种几何形状”,那肯定啊,不然就是陷入“白马非马”的误区了,你看编程不光学习IT知识,还能学习哲学,高深实在是在高深。(如果说“几何形状就是圆”那么就被笑话了)。
       不过有些继承类并不是只是改善了接口,会加入新的函数,所以不说完全等价,只是类似。
4.3      多形对象的互换使用
将衍生类的对象当做基础类的一个对象对待。这样只需要编写单一的代码,忽略类型特定细节,只与基础类打交道。
       举个栗子:
有如下的函数继承:

有这样一个函数
Void doStuff(Shape s){
       s.erase();
//…
       s.draw();
}
该函数与任何Shape通信,独立于它要draw和erase的任何特定类型的对象。
使用如下的代码是不会有什么问题的
Circle c = new Circle();
Triangle t = new Triangle();
Line l= new Line();
doStuff(c);
doStuff(t);
doStuff(l);
因为doStuff能发给一个消息给Shape,Circle也能接受的,所以上面函数是OK的。
       我们只要知道他是Shape,那么它必定可以进行doStuff函数的操作。如果此处需要根据圆形,三角形来进行不同的操作那不是很糟糕?对不对?
4.3.1       动态绑定
当draw消息发给一个匿名Shape时,根据Shape句柄当时链接的实际类型,会相应的采取正确的操作。将一条消息发给对象时,如果并不知道对方的具体类型是什么,但采取的行动同样是正确的,这种情况叫做多形性(Polymorphism). 用以实现多形性的方法叫作动态绑定。编译器和运行期系统会负责对所有细节的控制;我们只需知道会发生什么事情。在C++中好像动态绑定需要使用关键字virtual,而在JAVA中就不必了,完全是自动进行。
4.3.2       抽象的基础类和接口
基础类通常希望只为自己的衍生类提供接口,不想其他任何人实际创建基础类的对象。这个可以将类变成抽象的来实现,关键字 abstract。抽象方法被继承后,必须实现,否则继承的类也会变成抽象类。
 
5      关于对象的创建和存在时间
对象可以在堆栈或者静态存储空间里创建,也可以在内存池中创建。
5.1      集合和继承器
在内存池中创建对象,除非进行运行期不然就不知道到底需要多少个对象。在面向对象的设计中,大多数问题就是简单的创建另一种类型的对象。这个时候集合可以派上用处,集合也叫做容器。我们实现不必知道在一个集合里容下多少东西,只需创建一个集合,以后的工作让集合自己负责。
       C++中提供了标准模板库(STL)的形式,JAVA也用自己的标准库提供了集合。一个常规集合便可满足人们的大多数要求。所有集合都提供了相应的读写功能。
       如果需要对集合中的一系列元素进行操作或比较 ,就需要用到继续器Iterator,蛤蟆觉得是不是应该叫做迭代器啊??那就用E文吧,Iterator属于一种对象,负责选择集合内的元素,并把他们提供给集成器的用户。通过Iterator集合被抽象成一个简单的序列,允许我们遍历那个序列,而无需关心基础结构是什么。
       集合只是一个用来防止对象的储藏所,如果能满足我们的需要,就没必要关心它具体是如何实现的。
 
5.2      单根结构
JAVA中有个终极基础类,叫做Object。单根结构的所有对象都有一个通用的接口,最终都属于相同的类型。但是C++中并不能保证所有东西都属于相同的基本类型。
单根结构中的所有对象都可以保证拥有一些特定的功能。利用单根结构,可以更方便地实现一个垃圾收集器。与此有关的必要支持可安装于基础类中,而垃圾收集器可将适当的消息发给系统内任何对象。
       不过,单根结构会带来程序设计上的一些限制,同时加大了新程序与原有C代码兼容的按年度,所以当年C++决定放弃单根结构的做法,但是JAVA不同,JAVA是新事物,没有包袱,所以就使用单根结构了。
 
5.3      集合库与方便使用集合
集合是我们进程要用到的一个工具,所以及何库就十分必要,可以方便的重复使用。
刚才所说,单根结构意味着、所有东西归根结底都是一个对象。所以容纳了Object的一个集合实际可以容纳任何东西,这使我们对它的重复使用变得非常简便。
       不过这里不得不涉及到造型(Cast),怎么把这Object类型编程我们实际放入的那个类型呢?就是从普通到特殊的转换。造型有上塑和下塑两种,上溯是从特殊变为普通,例如Circle属于Shape,这个是毫无疑问正确的。下塑就是Shape属于Circle,这个就是有点不确切了,因为也有可能是Triangle.
       这就需要创建一个智能集合,知道自己容器的类型是什么。可以通过参数化类型,它们是编译器能自动定制的类,可与特定的类型配合。参数化类型是C++一个重要的组成部分,这个是C++没有单根结构的缘故。JAVA尚未提供参数化类型,也是由于使用了单根结构,显得有些笨拙。不过JAVA保留了generic关键字,可以用于未来实现。
 
5.4      清除困境
每个对象都要求资源才能生存,其中最明显的就是内存资源。如果不再使用就必须将其清除,以便释放这些资源。
       JAVA中,垃圾收集器在设计时已考虑到了内存的释放问题,垃圾收集器知道一个对象在什么时候不再使用,然后会自动释放那个对象占据的内存空间。由于JAVA的对象都是从单个根类继承,所有编程要比C++简单的多,只需要做出少量抉择,即可客服原先存在的大量障碍。
       任何事情都有两面性,在C++中,可以在堆栈中创建对象,这样对象得以自动清除,但是不具有在运行期间随心所欲创建对象的灵活性。同理,垃圾收集器能自动的清理内存空间,但是带来一个问题,JAVA程序执行期间会存在一种不连贯的因素,我永远不能确定什么时候启动或者要花多长时间。
       此外,JAVA比C++要简单,C++编程中在如果可以使用C就不会去使用C++,所以C++明显复杂。另一方面JAVA的简单,付出的代价就是失去了效率和一定程序的灵活性。
6      违例控制
错误控制一直都是设计者们需要解决的大问题。很多语言干脆将问题简单的忽略掉,将其转嫁给设计人员。
违例控制将错误控制方案内置到程序设计语言中,违例(Exception)属于一个特殊的对象,会从产生错误的地方扔 出来。
在JAVA中,违例控制模块是从一开始就封装好的,所以必须使用它。
违例控制并不属于面向对象的特性,虽然在面向对象的程序设计语言中,通常是用一个对象表示的。但是早在面向对象语言问世之前,违例控制就已经存在了。
 
7      多线程
计算机编程中,很多时候需要对多个任务加以控制。
       多线程操作最有价值的特性之一就是程序员不必关心到底使用了多少个处理器。程序在逻辑意义上被分割为数个线程。
       多个线程处理必须注意一个问题:共享资源。在试图同时访问一个资源的时候,就会遇到资源竞争,这就需要对资源进行锁定。
       JAVA的多线程机制已内建到语言中,使复杂的问题变得简单。JAVA对多线程处理的支持是在对象这一级支持的,一个执行线程可表达为一个对象。
 
8      永久性
有些对象在下次启动程序时,对象仍然,并能保留全部信息,是一件非常有价值的事情。
JAVA 提供了对有限永久性的支持,意味着我们可将对象简单的保存到磁盘上,以后任何时候都取回。称为有限,是由于我们仍然需要明确发出调用,进行对象的保存和取回工作。
9      Java和因特网
JAVA不但可以解决传统的程序设计问题,还能解决万维网上的编程问题。
9.1      C/S计算
客户机/服务器系统的基本思想是我们能在一个统一的地方集中存放信息资源。客户机/服务器概述的一个关键在于信息是“集中存放”的。能方便地更改信息,然后将修改过的信息发放给信息的消费者。在过去,我们一般为单独的问题采取单独的解决方案;每次都要设计一套新方案。这些方案无论创建还是使用都比较困难,用户每次都要学习和适应新界面。客户机/服务器问题需要从根本上加以变革!
9.2      Web服务器
Web实际就是一套规模巨大的客户机/服务器系统。
然后用户希望,某个信息可在任何类型的计算机上显示出来,毋需任何改动。这时的客户端本身只是一个纯粹的查看程序,连简单计算都不行(当然这个避开了病毒的骚扰)
客户端能力实在太弱,人们不得不对客户端进行编程。
 
9.3      客户端编程
“服务器-浏览器”方案可提供交互式内容,但这种交互能力完全由服务器提供,为服务器和因特网带来了不小的负担。服务器一般为客户浏览器产生静态网页,由后者简单地解释并显示出来。用户提交的信息通过所有Web服务器均能支持的“通用网关接口”(CGI)回传到服务器。
许多 Web站点都严格地建立在CGI的基础上,事实上几乎所有事情都可用CGI 做到。唯一的问题就是响应时间。CGI程序的响应取决于需要传送多少数据,以及服务器和因特网两方面的负担有多重。
我们按下网页上的提交按钮(Submit);数据回传给服务器;服务器启动一个CGI程序,检查用户输入是否有错;格式化一个HTML 页,通知可能遇到的错误,并将这个页回传给我们;随后必须回到原先那个表单页,再输入一遍。这种方法不仅速度非常慢,也显得非常繁琐。
解决的办法就是客户端的程序设计。运行Web 浏览器的大多数机器都拥有足够强的能力,可进行其他大量工作。客户端编程意味着Web浏览器可获得更充分的利用,并可有效改善Web服务器的交互(互动)能力。 对客户端编程的讨论与常规编程问题的讨论并没有太大的区别。采用的参数肯定是相同的,只是运行的平台不同:Web浏览器就象一个有限的操作系统。
9.3.1       插件
客户端编的一个问题就是插件的设计。利用插件可以方便地为浏览器添加新功能。这些代码的作用是告诉浏览器“从现在开始,你可以进行这些新活动了”。但插件的编写并不是一件简单的任务。
在构建一个特定的站点时,并不希望涉及这方面的工作。对客户端程序设计来说,插件的价值在于它允许专业程序员设计出一种新的语言,并将那种语言添加到浏览器,同时不必经过浏览器原创者的许可。由此可以看出,插件实际是浏览器的一个“后门”,允许创建新的客户端程序设计语言(尽管并非所有语言都是作为插件实现的)。
 
9.3.2       脚本编制语言
插件造成脚本语言的爆炸性增长。通过这种脚本语言,可将用于自己客户端程序的源码直接插入HTML页,而对那种语言进行解释的插件会在 HTML 页显示的时候自动激活。 
脚本语言的代码全部暴露在人们面前。
脚本语言真正面向的是特定类型问题的解决,其中主要涉及如何创建更丰富、更具有互动能力的图形用户界面(GUI)。
由于脚本编制语言的宗旨是尽可能地简化与快速,所以在考虑其他更复杂的方案之前(如Java 及ActiveX),首先应想一下脚本语言是否可行。目前讨论得最多的脚本编制语言包括JavaScript、VBScript以及Tcl/Tk。
JavaScript也许是目常用的,它得到的支持也最全面。很多浏览器目前都提供了对JavaScript 的支持。有些工具还能利用 JavaScript自动产生网页。
 
9.3.3       JAVA
如果说一种脚本编制语言能解决80%的客户端程序设计问题,那么剩下的20%又该怎么办呢?目前最流行的方案就是Java。一种功能强大、高度安全、可以跨平台使用以及国际通用的程序设计语言,也是一种具有旺盛生命力的语言。
对 Java 的扩展是不断进行的,提供的语言特性和库能够很好地解决传统语言不能解决的问题,比如多线程操作、数据库访问、连网程序设计以及分布式计算等等。
Java 通过“程序片”(Applet)巧妙地解决了客户端编程的问题。 程序片(或“小应用程序”)是一种非常小的程序,只能在Web浏览器中运行。作为Web页的一部分,程序片代码会自动下载回来(这和网页中的图片差不多)。
激活程序片后,它会执行一个程序。程序片的一个优点体现在:通过程序片,一旦用户需要客户软件,软件就可从服务器自动下载回来。它们能自动取得客户软件的最新版本,不会出错,也没有重新安装的麻烦。由于 Java 的设计原理,程序员只需要创建程序的一个版本,那个程序能在几乎所有计算机以及安装了 Java 解释器的浏览器中运行。
与脚本程序相比,Java 程序片的另一个优点是它采用编译好的形式,所以客户端看不到源码。在另一方面,反编译 Java 程序片也并不是件难事,而且代码的隐藏一般并不是个重要的问题。大家要注意另外两个重要的问题。
 
9.3.4       ActiveX 
在某种程度上,Java 的一个有力竞争对手应该是微软的 ActiveX,尽管它采用的是完全不同的一套实现机制。ActiveX最早是一种纯Windows的方案。经过一家独立的专业协会的努力,ActiveX 现在已具备了跨平台使用的能力。ActiveX 的意思是“假如你的程序同它的工作环境正常连接,它就能进入Web页,并在支持ActiveX 的浏览器中运行。ActiveX并没有限制我们使用一种特定的语言。假设我们是Windows程序员,能熟练地使用象
 C++、Visual Basic或者BorlandDelphi 那样的语言,就能几乎不加任何学习地创建出 ActiveX组件。 
 
9.3.5       安全 
自动下载和通过因特网运行程序是一个病毒制造者的梦想。在客户端的编程中,ActiveX带来了最让人头痛的安全问题。点击一个 Web站点的时候,可能会随同HTML 网页传回任何数量的东西:GIF 文件、脚本代码、编译好的Java 代码以及ActiveX 组件。有些是无害的;GIF文件不会对我们造成任何危害,而脚本编制语言通常在自己可做的事情上有着很大的限制。Java 也设计成在一个安全“沙箱”里在它的程序片中运行,这样可防止操作位于沙箱以外的磁盘或者内存区域。
ActiveX是所有这些里面最让人担心的。用 ActiveX编写程序就象编制 Windows应用程序——可以做自己想做的任何事情。下载回一个ActiveX组件后,它完全可能对我们磁盘上的文件造成破坏。当然,对那些下载回来并不限于在Web浏览器内部运行的程序,它们同样也可能破坏我们的系统。从 BBS下载回来的病毒一直是个大问题,但因特网的速度使得这个问题变得更加复杂。
目前解决的办法是“数字签名”,代码会得到权威机构的验证,显示出它的作者是谁。这一机制的基础是认为病毒之所以会传播,是由于它的编制者匿名的缘故。所以假如去掉了匿名的因素,所有设计者都不得不为它们的行为负责。这似乎是一个很好的主意,因为它使程序显得更加正规。
Java 通过“沙箱”来防止这些问题的发生。Java 解释器内嵌于我们本地的Web浏览器中,在程序片装载时会检查所有有嫌疑的指令。特别地,程序片根本没有权力将文件写进磁盘,或者删除文件(这是病毒最喜欢做的事情之一)。
 
9.3.6       因特网和内联网 
Web是解决客户机/服务器问题的一种常用方案。对于传统的客户机/服务器模式,面临的问题是拥有多种不同类型的客户计算机,而且很难安装新的客户软件。但通过 Web浏览器和客户端编程,这两类问题都可得到很好的解决。
若一个信息网络局限于一家特定的公司,那么在将Web技术应用于它之后,即可称其为“内联网”(Intranet),以示与国际性的“因特网”(Internet)有别。内联网提供了比因特网更大的安全级别,因为可以物理性地控制对公司内部服务器的使用。
安全问题将我们引入客户端编程领域一个似乎是自动形成的分支。若程序是在因特网上运行,由于无从知晓它会在什么平台上运行,所以编程时要特别留意,防范可能出现的编程错误。
面临客户端编程问题令人困惑的一系列解决方案时,最好的方案是先做一次投资/回报分析。总结出问题的全部制约因素,以及什么才是最快的方案。由于客户端程序设计仍然要编程,所以无论如何都该针对自己的特定情况采取最好的开发途径。
 
9.4      服务端编程
在传统意义上,服务器端编程是用Perl 和CGI脚本进行的,但更复杂的系统已经出现。其中包括基于Java 的Web服务器,它允许我们用Java进行所有服务器端编程,写出的程序就叫作“小服务程序”(Servlet)。
9.5      应用程序
Java 实际是一种常规用途的程序设计语言,可解决任何类型的问题,至少理论上如此。将视线从程序片身上转开(同时放宽一些限制,比如禁止写盘等),就进入了常规用途的应用程序的广阔领域。这种应用程序可独立运行,毋需浏览器,就象普通的执行程序那样。
在这儿,Java 的特色并不仅仅反应在它的移植能力,也反映在编程本身上。就象贯穿全书都会讲到的那样,Java 提供了许多有用的特性,使我们能在较短的时间里创建出比用从前的程序设计语言更健壮的程序。但要也要付出一些代价,其中最明显的是执行速度放慢了(尽管可对此进行多方面的调整)。Java 本身也存在一些限制,使得它不十分适合解决某些特殊的编程问题。Java 是一种正在快速发展的语言,随着每个新版本的发布,能充分解决的问题也变得越来越多。
 
9.6      分析和设计
面向对象的范式是思考程序设计时一种新的、而且全然不同的方式。事实上,可以作出一个“好”的设计,它能充分利用 OOP提供的所有优点。
OOP 的全部宗旨就是让软件开发的过程变得更加容易。 
大多数方法都设计用来解决最大范围内的问题。存在一些特别困难的项目,需要付出更为艰辛的努力。但是,大多数项目都是比较“常规”的,所以一般都能作出成功的分析与设计,而且只需用到推荐的一小部分方法。
无论多么有限,某些形式的处理总是有益的,这可使整个项目的开发更加容易,总比直接了当开始编码好! 

时刻提醒自己注意以下几个问题: 
(1) 对象是什么?(怎样将自己的项目分割成一系列单独的组件?)
(2) 它们的接口是什么?(需要将什么消息发给每一个对象?)
在确定了对象和它们的接口后,便可着手编写一个程序。出于对多方面原因的考虑,可能还需要比这更多的说明及文档,但要求掌握的资料绝对不能比这还少。
整个过程可划分为四个阶段,如下描述。
 
9.6.1       阶段0
第一步是决定在后面的过程中采取哪些步骤。如果计划本来就是“直接开始开始编码”,那样做当然也无可非议(若对自己要解决的问题已有很透彻的理解,便可考虑那样做)。但最低程度也应同意自己该有个计划。
有些程序员写程序时喜欢随心所欲,他们认为“该完成的时候自然会完成”。这样做刚开始可能不会有什么问题,但我觉得假如能在整个过程中设置几个标志,或者“路标”,将更有益于你集中注意力。在达到了一个又一个的目标,经过了一个接一个的路标以后,可对自己的进度有清晰的把握。
9.6.2       阶段1 拟出一个计划
在过程化中这个阶段称为“建立需求分析和系统规格”。需求分析的意思是“建立一系列规则,根据它判断任务什么时候完成,以及客户怎样才能满意”。
系统规格则表示“这里是一些具体的说明,让你知道程序需要做什么(而不是怎样做)才能满足要求”。需求分析实际就是你和客户之间的一份合约(即使客户就在本公司内部工作,或者是其他对象及系统)。
系统规格是对所面临问题的最高级别的一种揭示,我们依据它判断任务是否完成,以及需要花多长的时间。由于这些都需要取得参与者的一致同意,所以尽可能地简化它们,最好采用列表和基本图表的形式以节省时间。
我们特别要注意将重点放在这一阶段的核心问题上,不要纠缠于细枝末节。这个核心问题就是:决定采用什么系统。对这个问题,最有价值的工具就是一个名为“使用条件”的集合。对那些采用“假如……,系统该怎样做?”形式的问题,这便是最有说服力的回答。
尽可能总结出自己系统的一套完整的“使用条件”或者“应用场合”。一旦完成这个工作,就相当于摸清了想让系统完成的核心任务。由于将重点放在“使用条件”上,一个很好的效果就是它们总能让你放精力放在最关键的东西上,并防止自己分心于对完成任务关系不大的其他事情上面。只要掌握了一套完整的“使用条件”,就可以对自己的系统作出清晰的描述,并转移到下一个阶段。
用几个简单的段落对自己的系统作出描述,然后围绕它们再进行扩充,添加一些“名词”和“动词”。“名词”自然成为对象,而“动词”自然成为要整合到对象接口中的“方法”。只要亲自试着做一做,就会发现这是多么有用的一个工具;有些时候,它能帮助你完成绝大多数的工作。
尽管仍处在初级阶段,但这时的一些日程安排也可能会非常管用。我们现在对自己要构建的东西应该有了一个较全面的认识,所以可能已经感觉到了它大概会花多长的时间来完成。此时要考虑多方面的因素:如果估计出一个较长的日程,那么公司也许决定不再继续下去;或者一名主管已经估算出了这个项目要花多长的时间,并会试着影响你的估计。但无论如何,最好从一开始就草拟出一份“诚实”的时间表,以后再进行一些暂时难以作出的决策。目前有许多技术可帮助我们计算出准确的日程安排(就象那些预测股票市场起落的技术),但通常最好的方法还是依赖自己的经验和直觉(不要忘记,直觉也要建立在经验上)。感觉一下大概需要花多长的时间,然后将这个时间加倍,再加上
 10%。你的感觉可能是正确的;“也许”能在那个时间里完成。但“加倍”使那个时间更加充裕,“10%”的时间则用于进行最后的推敲和深化。但同时也要对此向上级主管作出适当的解释,无论对方有什么抱怨和修改,只要明确地告诉他们:这样的一个日程安排,只是我的一个估计!
 
9.6.3       阶段2 设计方案
在这一阶段,必须拿出一套设计方案,并解释其中包含的各类对象在外观上是什么样子,以及相互间是如何沟通的。此时可考虑采用一种特殊的图表工具:“统一建模语言”(UML)。当然并非一定要使用UML,但它对你会很有帮助,特别是在希望描绘一张详尽的图表,让许多人在一起研究的时候。除UML 外,还可选择对对象以及它们的接口进行文字化描述。
这个过程中最美妙的事情就是整个小组并不是通过学习一些抽象的例子来进行面向对象的设计,而是通过实践一个真正的设计来掌握OOP的窍门,而那个设计正是他们当时手上的工作! 作出了对对象以及它们的接口的说明后,就完成了第2 阶段的工作。当然,这些工作可能并不完全。有些工作可能要等到进入阶段 3才能得知。但这已经足够了。我们真正需要关心的是最终找出所有的对象。能早些发现当然好,但OOP提供了足够完美的结构,以后再找出它们也不迟。
 
 
9.6.4       阶段3 创建实施
在正式编码前掌握了正确的设计结构,所以会发现接下去的工作比一开始就埋头写程序要简单得多。而这正是我们想达到的目的。让代码做到我们想做的事情,这是所有程序项目最终的目标。但切不要急功冒进,否则只有得不偿失。根据我的经验,最后先拿出一套较为全面的方案,使其尽可能设想周全,能满足尽可能多的要求。
编程更象一门艺术,不能只是作为技术活来看待。所有付出最终都会得到回报。作为真正的程序员,这并非可有可无的一种素质。全面的思考、周密的准备、良好的构造不仅使程序更易构建与调试,也使其更易理解和维护,而那正是一套软件赢利的必要条件。
构建好系统,并令其运行起来后,必须进行实际检验,以前做的那些需求分析和系统规格便可派上用场了。
全面地考察自己的程序,确定提出的所有要求均已满足。
9.6.5       阶段4 维护或者成为校订
整个开发周期还没有结束,现在进入的是传统意义上称为“维护”的一个阶段。“维护”表示从“保持它按设想的轨道运行”、“加入客户从前忘了声明的功能”或者更传统的“除掉暴露出来的一切臭虫”等等意思。
大家对“维护”这个词产生了许多误解,有的人认为:凡是需要“维护”的东西,必定不是好的,或者是有缺陷的!因为这个词说明你实际构建的是一个非常“原始”的程序,以后需要频繁地作出改动、添加新的代码或者防止它的落后、退化等。因此,我们需要用一个更合理的词语来称呼以后需要继续的工作。
这个词便是“校订”。 “第一次做的东西并不完善,所以需为自己留下一个深入学习、认知的空间,再回过头去作一些改变”。对于要解决的问题,随着对它的学习和了解愈加深入,可能需要作出大量改动。进行这些工作的一个动力是随着不断的改革优化,终于能够从自己的努力中得到回报,无论这需要经历一个较短还是较长的时期。
由于多方面的原因,以后对程序的改动是必不可少。但必须确定改动能够方便和清楚地进行。不仅需要理解自己构建的是什么,也要理解程序如何不断地进化。
面向对象的程序设计语言特别适合进行这类连续作出的修改——由对象建立起来的边界可有效保证结构的整体性,并能防范对无关对象进行的无谓干扰、破坏。也可以对自己的程序作一些看似激烈的大变动,同时不会破坏程序的整体性,不会波及到其他代码。事实上,对“校订”的支持是OOP非常重要的一个特点。
通过校订,可创建出至少接近自己设想的东西。然后从整体上观察自己的作品,把它与自己的要求比较,看看还短缺什么。然后就可以从容地回过头去,对程序中不恰当的部分进行重新设计和重新实现。
在最终得到一套恰当的方案之前,可能需要解决一些不能回避的问题,或者至少解决问题的一个方面。而且一般要多“校订”几次才行。
反复的“校订”同“递增开发”有关密不可分的关系。递增开发意味着先从系统的核心入手,将其作为一个框架实现,以后要在这个框架的基础上逐渐建立起系统剩余的部分。随后,将准备提供的各种功能(特性)一个接一个地加入其中。
     此时应着眼于建立一个简单、明了的版本,使自己能对系统有个清楚的把握。再把这个原型扔掉,并正式地构建一个。快速造型最麻烦的一种情况就是人们不将原型扔掉,而是直接在它的基础上建造。如果再加上程序化设计中“结构”的缺乏,就会导致一个混乱的系统,致使维护成本增加。
 
9.6.6       计划回报
如果没有仔细拟定的设计图,当然不可能建起一所房子。如建立的是一所狗舍,尽管设计图可以不必那么详尽,但仍然需要一些草图,以做到心中有数。
软件开发则完全不同,它的“设计图”(计划)必须详尽而完备。在很长的一段时间里,人们在他们的开发过程中并没有太多的结构,但那些大型项目很容易就会遭致失败。通过不断的摸索,人们掌握了数量众多的结构和详细资料。但它们的使用却使人提心吊胆在意——似乎需要把自己的大多数时间花在编写文档上,而没有多少时间来编程(经常如此)。需要采取一种最适合自己需要(以及习惯)的方法。不管制订出的计划有多么小,但与完全没有计划相比,一些形式的计划会极大改善你的项目。
请记住:根据估计,没有计划的50%以上的项目都会失败!
 
9.7      JAVA和C++
Java 特别象C++;由此很自然地会得出一个结论:C++似乎会被Java 取代。 
无论如何,C++仍有一些特性是Java 没有的。而且尽管已有大量保证,声称Java有一天会达到或超过C++的速度。但这个突破迄今仍未实现(尽管Java 的速度确实在稳步提高,但仍未达到C++的速度)。此外,许多领域都存在为数众多的 C++爱好者,所以我并不认为那种语言很快就会被另一种语言替代(爱好者的力量是容忽视的。
Java 强大之处反映在与 C++稍有不同的领域。C++是一种绝对不会试图迎合某个模子的语言。特别是它的形式可以变化多端,以解决不同类型的问题。这主要反映在象Microsoft Visual C++和Borland C++ Builder那样的工具身上。
它们将库、组件模型以及代码生成工具等合成到一起,以开发视窗化的末端用户应用(用于Microsoft Windows操作系统)。但在另一方面,Windows开发人员最常用的是什么呢?是微软的Visual Basic(VB)。从语言设计的角度看,尽管VB是那样成功和流行,但仍然存在不少的缺点。最好能够同时拥有 VB 那样的强大功能和易用性,同时不要产生难于管理的代码。而这正是Java 最吸引人的地方:作为“下一代的 VB”。人们对Java 做了大量的工作,使它能方便程序员解决应用级问题(如连网和跨平台UI等),所以它在本质上允许人们创建非常大型和灵活的代码主体。同时,考虑到Java还拥有我迄今为止尚未在其他任何一种语言里见到的最“健壮”的类型检查及错误控制系统,所以Java
 确实能大大提高我们的编程效率。 
但对于自己某个特定的项目,真的可以不假思索地将 C++换成Java 吗?除了Web程序片,还有两个问题需要考虑。首先,假如要使用大量现有的库(这样肯定可以提高不少的效率),或者已经有了一个坚实的C或C++代码库,那么换成 Java 后,反映会阻碍开发进度,而不是加快它的速度。但若想从头开始构建自己的所有代码,那么Java 的简单易用就能有效地缩短开发时间。
最大的问题是速度。在原始的Java 解释器中,解释过的Java 会比C慢上20到50倍。尽管经过长时间的发展,这个速度有一定程度的提高,但和C比起来仍然很悬殊。计算机最注重的就是速度;假如在一台计算机上不能明显较快地干活,那么还不如用手做(有人建议在开发期间使用Java,以缩短开发时间。然后用一个工具和支撑库将代码转换成C++,这样可获得更快的执行速度)。
为使Java 适用于大多数Web 开发项目,关键在于速度上的改善。此时要用到人们称为“刚好及时”(Just-InTime,或JIT)的编译器,甚至考虑更低级的代码编译器。当然,低级代码编译器会使编译好的程序不能跨平台执行,但同时也带来了速度上的提升。这个速度甚至接近 C和C++。而且Java 中的程序交叉编译应当比C 和C++中简单得多(理论上只需重编译即可,但实际仍较难实现;其他语言也曾作出类似的保证)。
 

猜你喜欢

转载自blog.csdn.net/weixin_43271086/article/details/90735034