面向对象设计与构造第三次课程总结

  相比前两个单元的作业,这个单元的作业在我们对Java语言的使用有了一定的了解的基础上,主要针对JSF这种Java的设计规范表达方式的使用进行了训练,旨在进一步提升编码时的工程化思维和方法的使用。

程序规格化设计发展简介


产生背景

  1950年代—1960年代初,手工艺式的程序设计方法,高德纳把程序称为艺术品。
  1960年代末—1970年代初,出现软件危机:一方面需要大量的软件系统,如操作系统、数据库管理系统; 另一方面,软件研制周期长,可靠性差,维护困难。编程的重点:希望编写出的程序结构清晰、易阅读、易修改、易验证,即得到好结构的程序。
  1968年,北大西洋公约组织(NATO)在西德召开了第一次软件工程会议,分析了危机的局面,研究了问题的根源,第一次提出了用工程学的办法解决软件研制和生产的问题,本次会议可以算做是软件发展史上的一个重要的里程碑。
  1969年,国际信息处理协会(IFIP)成立了“程序设计方法学工作组”,专门研究程序设计方法学,程序设计从手工艺式向工程化的方法迈进。

结构化研究

  1968 年,结构化程序设计方法的研究。Dijkstra 提出了“GOTO是有害的”,希望通过程序的静态结构的良好性保证程序的动态运行的正确性。
  1969 年,Wirth 提出采用“ 自顶向下逐步求精、分而治之” 的原则进行大型程序的设计。其基本思想是:从欲求解的原问题出发,运用科学抽象的方法,把它分解成若干相对独立的小问题,依次细化,直至各个小问题获得解决为止。

程序正确性证明

  1967年,Floyd 提出用“ 断言法” 证明框图程序的正确性。
  1969年,Hoare 在Floyd 的基础上,定义了一个小语言和一个逻辑系统。此逻辑系统含有程序公理和推导规则,目的在于证明程序的部分正确性,这就是著名的Hoare逻辑。他的工作为公理学语义的研究奠定了基础。
  1973年,Hoare和Wirth把PASCAL语言的大部分公理化。
  1975年,一个基于公理和推导规则的自动验证系统首次出现。
  1979年,出现了用公理化思想定义的程序设计语言Euclid。
  1976年,Dijkstra提出了最弱前置谓词和谓词转换器的概念,用于进行程序的正确性证明和程序的形式化推导。
  1980年,D.Gries综合了以谓词演算为基础的证明系统,称之为“程序设计科学”。首次把程序设计从经验、技术升华为科学。
  1974年,人们利用模态逻辑验证并行程序的正确性。

构造正确的程序

  利用Dijkstra 的谓词转换器及其演算规则集合,可以推导出正确的程序。
  利用程序变化构造正确的程序。它对程序应用一连串的保护正确性的变换规则,最终得到可执行的程序。程序变换是1970年代以来,“程序设计方法学” 研究的重要方面,是程序设计自动化很有希望的途径之一。递归程序变换是这一时期的最有意义的成果。 如Burstall 和Darlington 的递归程序变换系统等。
  逻辑程序设计和函数程序设计代表一种新的研究方向。Prolog是以谓词逻辑的子集(Hoare 子句)为基础的一种形式系统。Prolog 的执行过程就是执行逻辑上消解算法的过程。


规格bug分析

bug未被发现


改进jsf写法


前置条件

  1. 传入的参数是基本数据类型的情况下,如果没有其他外部的限制,并且在方法中并不会涉及数据的溢出,建议记为(以传入一个int为例)
    1 /*
    2  *\exist int x
    3  */
    View Code

    这样一来既没有忽略参数的存在,二来也避免了对理解代码无益的加上Integer.MAX_VALUE类似的限制。

  2. 传入对象的场合,无论何种情况都要加上null相关的判别。如果方法内没有容错处理,就必须要在前置条件中加以限制。
  3. 尽量避免在前置条件中对参数加上this的限制,因为也许在当前版本中只有当前类中的成员变量才能作为参数传入,但是若在以后的更新中这个方法可以传入外部其他参数时,就会与先前的设计规范产生冲突。
  4. 前置条件与具体实现中应尽可能降低重合度,一来确保设计规范和具体实现的一致性,二来为了保证程序的效率,避免浪费资源重复运行实质等价的代码。
  5. 线程安全方面的前置条件,应明确指出冲突区资源在锁定前的情况,比如在同步的情况下应指出先前可能的资源占用者,在阻塞时应明确指出阻塞带来的后果。

后置条件

  1. 对于方法的作用只是周期性地改变某些量,改变的过程就是方法的后置条件本身的情况时,建议用类似于自然语言描述状态机的格式,不重不漏地表达出来
  2. 对于后置条件为某些系统调用的情况(System.out,文件读写等),建议对这些行为的JSF描述做一个规范(最好是具有共识的表述),这样就能把“print的四种JSF写法”的进一步规范化了。
  3. toString方法往往只是对对象信息的一个整理,如果要把具体返回的string的内容写出来,就跟具体实现无异了。因此这样的情况要避免。
  4. 构造方法的后置条件的书写,建议采用如下格式以提高可读性:
    /*
     *\result=({a, b, c}←{_a, _b, _c})
     */

    构造方法中往往主题是几个量的赋值,在赋值的变量不太多时,这样的格式确实能提高可读性。

  5. 线程安全方面的后置条件,应明确指出资源在被锁定期间,会有其他的何种可能的对被锁定资源的访问,会使那些线程被阻塞。

bug聚集分析


仅在第11次作业中发现bug

类:FileLoader,方法:public void Go(),功能bug 1个,规格bug 0个

bug具体内容:LoadFile时对初始化设置为接单和派单状态的情况全部强制归到等待服务状态。应改为自定义的接单派单过程。

感想


  从我个人的学习体验来看,JSF训练的出发点很好,但是实际上还有需要完善的地方。规范化,本应是为了多快好省地写出优质代码而存在的,但是实际上用了JSF未必能多快好省。首先,作业中出现了先写代码再补规范的情况,很大程度上失去了规范本身在程序设计上的作用。于我个人而言,我在写程序前都会按照自己的思路,用自然语言写出大致的功能实现路径和步骤,一般而言仅仅涉及目的、具体功能、核心数据结构与算法等,并不会像JSF这样重视局部细节。重视局部细节(如null相关,代码容错,异常处理等)的部分应在方法主体的思路确定以后才能进一步完善——换言之设计应该有两个阶段:解决矛盾的主要方面的阶段(功能),以及矛盾的次要方面的阶段(逻辑完备性),这样的思路往往更有利于以目标为导向的编码。很不幸,JSF本身并没有区分二者的意图。

  其次,从可读性来看,一阶逻辑的可读性是远不及自然语言的。这就对大型项目的团队协作造成了不便。一个大项目分成若干个部分来实现的时候,明确的是每一块的具体功能,越明晰越好,但是目前JSF的使用情况似乎并不是这样。

  最后,从维护性来看,JSF往往会把具体实现的结果用繁杂的布尔表达式表现出来。如果初期设计上就特别注重模块化的实现的话,那么我只需要用自然语言简洁而又完备地描述下具体模块的状态变化即可。这样的代码在维护时也便于上手。

猜你喜欢

转载自www.cnblogs.com/stand-alone-complex/p/9111774.html
今日推荐