程序设计规格化的思考
程序设计是从汇编时代开始的,我们的学习过程也同样是从面相过程编程慢慢的转换到面向对象编程。但语言的发展没有止步,就离我们最近的c++而言,几乎每年都在更新它的标准与特性。
但我们同时需要认识到两件事:1.虽然标准与特性在改变,但是语言还在极大的兼容着以前的一些特性。2.语言的变化并没有带来最底层的编译原理的变化。
因此对于以上两点,程序员的开发过程慢慢变得从具体的对象化编程变成了抽象化开发以及面向接口编程。这样更加有利于众多程序员的共同开发过程。
至于老师ppt上提到的规格化。。好像这个词是五月二十五号突然出现的一样。是不是翻译比较特殊?
所被报告的规格的bug:
测评的人反复挂了同一个bug,并且。嗯没了
出现bug的原因
1.开始时规格书写不规范
第一次没有仔细看JSF说明犯了很多错误…并且上网没查到正确的写作方法。
2.使用了自然语言描述
第一次时使用了自然语言描述,在OO第五次课上实验后,因为提供的代码中有很多规范的JSF书写,所以才学会了该怎么写,但是此时EFFECTS部分我的理解还不对,很多地方留了空,并且理解错了OVERVIEW的功能,幸运的是测试者理解、接受了我的想法,没有在JSF上扣太多而是把测试和讨论重点放在了代码本身上;后来在第十一次作业我也尽快改正了以上的问题。
3.代码思路不规范
如果使用了面向抽象编程的思想:例如把排序抽象出来,就可以写格式化的JSF了。
不好的写法
public Light(TaxiGUI gui) { /** * @REQUIRES: None; * @MODIFIES: this; * @EFFECTS: this.gui == gui; */ this.gui = gui; }
修改:将requires修改为gui!=null。
不好的写法
public Taxi(int index, TaxiGUI gui,Light light) { /** * @REQUIRES: 0<=index<=99, gui != null, light != null; * @MODIFIES: this; * @EFFECTS: Initialize the attributes of this class; */ this.index = index; this.status = 2; this.credit = 0; this.x = new Random().nextInt(80); this.y = new Random().nextInt(80); this.face = new Random().nextInt(4); this.gui = gui; this.light = light; gui.SetTaxiStatus(index, new Point(x,y), status); }
好的写法:
public Taxi(int index, TaxiGUI gui,Light light) { /** * @REQUIRES: 0<=index<=99, gui != null, light != null; * @MODIFIES: this; * @EFFECTS: this.index == index, this.status == 2, this.credit == 0, this.x == Random().nextInt(80), * this.y == Random().nextInt(80), this.face = Random().nextInt(4), this.gui == gui, this.light == light; * set the taxi in map. */ this.index = index; this.status = 2; this.credit = 0; this.x = new Random().nextInt(80); this.y = new Random().nextInt(80); this.face = new Random().nextInt(4); this.gui = gui; this.light = light; gui.SetTaxiStatus(index, new Point(x,y), status); }
不好的写法:
1 public void credit_increase(int n) { 2 /** 3 * @REQUIRES: n == 1 || n == 3; 4 * @MODIFIES: credit; 5 * @EFFECTS: increase the credit; 6 */ 7 credit += n; 8 }
好的写法:
1 public void credit_increase(int n) { 2 /** 3 * @REQUIRES: n == 1 || n == 3; 4 * @MODIFIES: credit; 5 * @EFFECTS: credit == \old(credit) + n; 6 */ 7 credit += n; 8 }
此外我认为。。modified应该是synchronized的对象而不是this。
其他
我记得我再看神经网络的时候有人介绍说没有绝对优势的神经网络模型,所有的模型可能只是在匹配某些特定的数据上有着特别的优势。现在看到面向对象我们自己需要创造一个结构的时候,稍微的理解了一点这部分的内容。可能我们所实现的结构的空间复杂度非常的小或者时间复杂度小,类也少,继承和派生类也很少。但是。。这阻挡不了程序的可扩展性非常的差。
在写前几次作业的时候我没有想过后来的红绿灯和道路流量的相关问题。在每次的作业中我也尽可能的使用GUI进行开发,仿佛GUI是万能的。GUI确实很好用,但是GUI的最大的问题在于可拓展性。助教只是随手写下的一个代码,我们也不考虑扩展的问题,因此每次对着相同的数据结构重新写类似的代码还是很苦恼的。
第9次作业 出租车
第九次作业相比第七次作业增加了流量要求。在做这次的作业之前,我跟同学讨论的过程中同学认为应该对每一条道路或者每一个节点创建一个对象,红绿灯基于该节点存在。而我采用了GUI所提供的bool形的6400×6400的矩阵。当然这为后来的内容埋下了隐患按下不表。
个人感觉到了第九次作业大家的代码虽然差距很大,但是大家的技术差距不算大。有一些显而易见的内容没有被挑出来,而一些无关紧要的bug却抓的很紧。可能互测能力还略有欠缺。至于指导书所提到的“用户保证xx的合格”反而成为了大家故意测试溢出的地方。
在这次作业中,我仍然使用了gui的静态变量guigv进行访问流量信息与流量变化。实际上减少了工作量,但增加了taxi类的代码行数。taxi的代码行数几乎成为了其他类的两倍。
第十次作业。
在第十次作业中,依据指导书的要求创建了红绿灯。在发现不能继续使用gui之后,我创建了一个红绿灯类。
在抽象的过程中,我将很大一部分的共享代码提取出来减少代码的工程量。之前完全基于gui的道路系统和红绿灯系统已经产生了相关的改变。
我不希望在每一次传递参数的过程中(例如taxi的读取)过程中都需要重新调用参数,因此我对Traffic使用了单例的构造形式。
以下为单例的trafficlight (部分代码,已删除jsf相关部分)
public class TrafficLight extends Thread { private static TrafficLight trafficLight = null; private int[][] lightstate; private TaxiGUI taxigui; public static int ChangeTime; private TrafficLight() {// 单例模式 setChangeTime(); } public void settaxigui(TaxiGUI taxigui){ this.taxigui = taxigui; } public static TrafficLight GetTrafficLight() { if (trafficLight == null) trafficLight = new TrafficLight(); return trafficLight; } }
使用单例化的trafficlight能够减少参数的传递,并且保证只有一个线程正在工作。关于此次的jsf作业,大量使用了自然语言描述。然而实际上,jsf在写的过程中在一定程度上要求了程序员需要使用抽象画的编程方法,否则jsf很难以正确的方式写清楚。至于repOK,repOK所谓的代码前后不变量实际上是被以自然语言的方式进行构造的。不变量如果在代码中间被改变,是否还需要保证repOK的正确性?如果不是,代码中间的状态是否通过临时变量来表现?
第十一次作业
在第十一次作业中,依据指导书更改了流量的相关内容和创造了一个新的可监控出租车。因为我的可监控出租车的监控方式产生了变化,因此可监控出租车类面临很多的代码重写的工作。可以看到新出租车里复制且重写了很多相关的代码。
在相互批改作业的时候,我对我抽到的代码抱有比较大的意见。因为在满灯的情况下,该代码可以创造出6400个线程,gui的刷新方式也是异步刷新。因此卡顿现象严重。
修改思路及其他
1.关于taxi类的修改思路
taxi有四个状态。状态的标记可以用四个宏来表示,也可以用一个enum来表示。
taxi四个状态的处理函数不应该写在run里面,我个人认为可以创建四个抽象接口,使用接口的形式访问这些动作。这样平衡了代码行数,便于debug与代码共享。
2.关于地图与流量的修改思路
地图和流量建议使用单独的类进行编辑,并使用单例模式进行相关的修改。
面向对象的编程方式已经逐渐变成了面向抽象的编程方式。仿佛我们目前所写的已经从一个具体项目变成了造轮子。可能这是一种奇特的思路吧