面向对象课程作业1-3总结分析
将近一个月的面向对象学习,作为一个JAVA新晋选手,针对把“面向过程式封装”思维逐步过渡为“基于数据管理与分工交互的面向对象”思维的努力从未止步,回首前三次作业的学习痕迹,看到的不只是自己进步的过程,更是提高的空间。
设计技巧总结
加强设计鲁棒性的基础——基于正则的错误输入的准确识别与反馈
一个程序想要正确运行的重要前提是对异常输入的识别和拦截。关于正则表达式的语法学习不再赘述。
通过三次练习,结合自己和被测程序的设计思路可以发现,使用正则表达式识别错误主要有两种思路——整体匹配和局部位置匹配,在实践过程中发现使用两者各有优缺点。
当不需要非常准确的定位输入的错误位置时,我们更倾向于整体匹配。整体匹配是一种正向思路,对完整正确的输入模式进行格式概括,设计出匹配表达式,当输入与表达式不能无缝匹配时,说明输入不符合要求。优点是不用分类穷举所有的错误情形,减少了穷举不全的失误,非黑即白的有限衡量标准使得在各类非法测试中表现的非常稳。当正确输入的标准可以适当放宽时易修改,同时避免纳新后的误判。缺点是不易定位出不合规定的错误输入位置,稍显不友好,如果整体匹配代码设计不佳长度过长在大规模输入中可能爆栈。
我们以电梯类的整体匹配输入检测为例,可以发现所有合法输入通过这四个表达式即可完全描述,简洁清晰。
1 private String checkpattern_1="^\\(FR\\,(\\+)?0{0,}1\\,UP\\,(\\+)?0{0,}(\\d+)\\)$"; 2 private String checkpattern_2="^\\(FR\\,(\\+)?0{0,}10\\,DOWN\\,(\\+)?0{0,}(\\d+)\\)$"; 3 private String checkpattern_3="^\\(FR\\,(\\+)?0{0,}[2-9]\\,(UP|DOWN)\\,(\\+)?0{0,}(\\d+)\\)$"; 4 private String checkpattern_4="^\\(ER\\,(\\+)?0{0,}([1-9]|10)\\,(\\+)?0{0,}(\\d+)\\)$";
如果修改楼层范围、上下行命令限制、前导0的个数和符号限制等,非常少的改动即可实现。注意此处^....$的正则组合用于限制正确输入的开头结尾符号,避免匹配到一个非法表达式的正确子串,导致判断错误。
如果想将错误定位细化到返回错误字符周围环境,且字符种类比较少、字符搭配限定较局限时,位置匹配是一种比较好的策略。它列举每一种字符前后的合法搭配,巧用^,使得如果有匹配结果说明存在非法搭配,必要时返回匹配到的字符串即可。优点是定位准确便于输入者修改,缺点却比较明显,当字符串种类多且搭配广泛时,难免存在列举遗漏,BUG也就被挂在树上了。
我们以多项式计算程序输入为例,一种识别“(”的位置检查设计和实验结果如下:
2 String pattern ="\\([^\\d\\+\\-]"; 再配合数字的位置合法性判断,当输入为{1,(1,2)}时,输出为 #1,(
重用代码封装,简化信息传递,营造类的专属“内部生态”
重用代码封装——修改少,逻辑清
我们对不同的信息类型处理虽然不尽相同,但模式上是大同小异的。多项式对多项式的信息抽取、结果记录过程是一样的,运算过程只有一个‘+’、‘-’之别,完全可以将相同操作合并。电梯的FR、ER请求信息虽然不同,但都可以抽象为请求类,使用一套相同的属性设计去刻画。捎带电梯处理一条主请求和一条捎带请求虽然对一些状态的修改不完全一致,但运行一条指令并删除其同质指令的流程是一致的,如果完全割裂直接分两类,那么给电梯解析请求并发送指令以及删除同质指令的代码就会被重复书写,一旦设计存在漏洞,需要修改多处,代码量大就很容易疏忽掉一处,在少量测试下不易发现,埋下了隐患。
简化信息传递——交互智能,安全性强
有些信息不必暴露在其他类面前,因为类的内部对自身变量的分析可以给出传达给外部的内部状态,而其他类只要获知这种状态就知道自己的行动目标了,解析的过程是一种冗余,对数据存储也不安全,不便于调试。例如调度类和电梯类的交互,电梯不必获知调度类目前正在解析的指令是FR还是ER等详细信息,不需要记录自己执行过的指令历史,只需要听从调度类有限输出信息的指挥,知道自己要去几楼即可,而调度类也只需要知道电梯的当前时间、上下状态、预计到达各个楼层的时间即可为电梯准备下一个command,至于记录下上一调指令的信息便于筛选下一条是调度类的“份内之事”,不需要和别人商量,尽可能少的变量共享也就意味着减少误修改、降低分析复杂度,因为分工明确,变量私有,内部运营,DEBUG调试也轻松许多。
营造类的专属“内部生态”——测试完备,定位轻松
如果一个类可以“自给自足的”提供启动信息、输出运营结果,那么测试类的功能性就变得很简单。测试技巧是在类的内部设计一个main函数,每写完一个就进行功能测试,把BUG消灭在底层,防止整个工程build后漏洞百出在整体的视角分段debug。
给方法买人身保险——try-catch维持程序稳定性
设计时把每个方法都放到try-catch里面并进行一定的容错处理,输出自己设定的报错信息并使程序正常退出实是明智之举。一方面彻底排除crash的可能性,增强程序运行的稳定性可靠性,一方面运行后如果出现异常,会输出自己预先设计好的信息,直接可以定位到出错的方法,给猜想错误原因环节和调试修改环节带来了很多方便。使用格式举例:
1 · try{ 2 .....代码.......... 3 }catch(Exception e) { 4 System.out.println("# calculate函数出现异常"); 5 System.exit(0);//容错机制可以根据需要设计 6 }catch(Error e) { 7 System.out.println("# calculate函数出现错误"); 8 System.exit(0); 9 }
统一基础上的个性化——继承
以课上公司员工和课下电梯调度类为例,这种调用父类的有层次感的方式非常易于创造出统一性和个性化兼备的代码逻辑,便于修改,同时可以实现父类和子类的切换。应该注意的是继承关系中构造函数的使用。
(1)子类的构造过程中必须调用其父类的构造方法。 (2)子类可以在自己的构造方法中使用 super(argument_list)调用父类的构造方法,也使用 this(argument_list)调用本类的另外构造方法。如果调用 super,必须写在子类构造方法的第一行。 (3)如果子类的构造方法中没有显式调用父类的构造方法,则系统默认调用父类的无参数构造方法。 (4)如果子类构造方法中既没有显式调用父类的构造方法,而父类又没有无参数的构造方法,则编译出错。
其他设计技巧——变量名设计有讲究。自然语言记录设计灵感,施工按照图纸。使用PMD等工具对自己的代码进行评估。
变量名设计不能随意,否则很可能造成写代码过程中变量名误写,尤其是当错误变量名也存在时,BUG就在不知不觉中产生了。可以巧用'_'连接,缩写易于识别,名称表达变量的特点、用途。
有些逻辑比较复杂的工程比如说电梯设计不建议直接上手写代码,一个可参考的方法是在文档中用自然语言或图表写明设计框架,大概包括类的分工、一个类管理的属性和各个方法接收的信息、主要内部运营逻辑、传达出的信息效果以及方法间、对象之间信息交互的机制检查后再开始写码,这种方式对间断完成工程、逻辑debug提高效率非常有效。
根据PMD反馈的查重复结果,可以提示我们将重复的部分进行封装。他提示的if-else switch缺失等信息,也可以帮助我们尽快消灭潜在却很难注意到的BUG。
【关于DEBUG...】
关于if-else:可以使用断点调试对可疑处单步运行,也可以设计标记变量测试是否进入该条件如果没有就要查看哪个变量错误导致条件不满足。
关于跟踪变量:重点跟踪定位其在多个方法调用前后的区别,对比查看到异常变化。
关于类的数组不易查看的属性内容:可以先跟踪某一个存入数组前变量的值,如发现没有异常再使用数组下标遍历对象法查看实际存储值。
作业自检改进与BUG修复
作业1——多项式运算
作业重难点总结:
主要是初学者对正则表达式的学习使用,尤其是多次匹配一个字符等正则表达方案,正则表达式表达漏洞很有可能导致意想不到的BUG。正则表达式匹配函数的使用,常用匹配函数如下。
一个Matcher对象是一个状态机器,它依据Pattern对象做为匹配模式对字符串展开匹配检查。首先一个Pattern实例订制了一个所用语法与 PERL的类似的正则表达式经编译后的模式,然后一个Matcher实例在这个给定的Pattern实例的模式控制下进行字符串的匹配工作。
(以上两图来自网络,不算太全面,放在这里可以方便大家查阅)
关于匹配次数:
[] 由方括号内的一个字符列表创建的自定义字符类 . 匹配任何单个字符 下面的字符将用于控制将一个子模式应用到匹配次数的过程: ? 重复前面的子模式0次到一次 * 重复前面的子模式0次或多次 + 重复前面的子模式一次到多次
笔者记性不太好所以emmmmmmmm就把自己用的几个肥肠常见的代码段贴在这里以后直接用嘿嘿嘿嘿 -_-
* 匹配并把匹配结果放到一个数组里面:
1 Pattern p = Pattern.compile("([/+/-]?\\d+)|[\\-\\+]"); 2 3 Matcher m = p.matcher(str); 4 5 List<String> strlist = new ArrayList<String>(); 6 7 while(m.find()) { 8 strlist.add(m.group()); 9 } 10 11 Str = new String[strlist.size()]; 12 13 int i=0; 14 for(String string : strlist) { 15 Str[i] = string; 16 i++; 17 }
* 读入一波字符串并进行一定的操作
1 Scanner sc = new Scanner(System.in); 2 String str=null; 3 4 if(sc.hasNextLine()) { 5 str = sc.nextLine();
//进行某种不为人知的操作 @_@ 6 } 7 sc.close(); //一定不要忘了阿!!!!!
* 关于一个字符串可能不方便一次性输出但需要在视觉上是一行:
System.out.print() 结尾没有换行符,很适合输出半句话
System.out.println()结尾有换行符,适合输出行尾
输出时使用一个String变量拼接一个字符串是一个很好的办法,JAVA里面的‘+’简直不能再好用了QAQ!!
问题代码段1:
1 public class ComputePoly{ 2 3 public void computer() { 4 Poly temp=new Poly(Split.len+1); 5 for(int i=0;i<Split.len+1;i++) {
6 temp.term[i]=Split.PolyList[0].term[i];
7 } 8 9 省略计算过程 10 ...... 11 } 12 public void print() {
打印结果 13 ..... 14 } 15 }
待提升提升技能点:1、多项式计算类直接访问split产生的public多项式数组属性,且修改了第一个数组元素的值,非常不安全。
2、第一次写面向对象程序,实际上是“披着面向对象外衣的面向过程程序”,对计算类的分工不太明确,将print方法一并写入了计算多项式类的方法中。
解决方案:1、将split类数组属性设为Private但提供查看方法,值不允许写入到第一个数组元素的位置,而是在ComputePoly类设计一个保存结果的Poly类的对象。
2、ComputePoly类对外提供访问private结果属性的方法,打印通过另一个类调用这个方法获取信息并拼接字符串来实现。
问题代码段2: check方法中的20个对不同类符号位置合法性判断的方法,举其中两个说明问题
1 public void _1(String str) { 2 String pattern ="[^\\d\\)],"; 3 4 Pattern r = Pattern.compile(pattern); 5 6 Matcher m = r.matcher(str); 7 8 List<String> ComLeList = new ArrayList<String>(); 9 int flag=0; 10 while(m.find()) { 11 flag=1; 12 ComLeList.add(m.group()); 13 } 14 String[] ComLeBug = new String[ComLeList.size()]; 15 int i = 0; 16 for(String ComBug:ComLeList) { 17 ComLeBug[i] = ComBug; 18 i++; 19 } 20 if(flag==1) { 21 System.out.println("ERROR"); 22 for(int j=0;j<ComLeBug.length;j++) { 23 System.out.println("#"+ComLeBug[j]); 24 } 25 exit=1; 26 } 27 } 28 29 public void _2(String str) { 30 String pattern =",[^\\(\\d\\+\\-]"; 31 32 Pattern r = Pattern.compile(pattern); 33 34 Matcher m = r.matcher(str); 35 36 List<String> ComLeList = new ArrayList<String>(); 37 int flag=0; 38 while(m.find()) { 39 flag=1; 40 ComLeList.add(m.group()); 41 } 42 String[] ComLeBug = new String[ComLeList.size()]; 43 int i = 0; 44 for(String ComBug:ComLeList) { 45 ComLeBug[i] = ComBug; 46 i++; 47 } 48 if(flag==1) { 49 System.out.println("ERROR"); 50 for(int j=0;j<ComLeBug.length;j++) { 51 System.out.println("#"+ComLeBug[j]); 52 } 53 exit=1; 54 } 55 }
解决方案:”方法间只有匹配串不同而检测逻辑完全相同,所以应该封装为一个以匹配正则串和待检测字符串为参数的方法。通过多次调用减少代码无用重复。
其他待提升技能点:善用try catch。
【BUG修复】
BUG: 输入:{(1,2 错误输出:{(1,2)}
输入 : { 错误结果:crash
出错原因分析:局部位置匹配法设计出的正则匹配串用于检索匹配到其他字符的情况,但如果是旁边缺失则很难发现,甚至认为是正确输入继续计算,gg了。
方案修正:首先在这种环境下选用整体匹配可以使代码健壮性更强,如果一定要使用局部位置匹配需要对括号这种必须成对出现的符号有单独判断。最佳方案是使用整体匹配判断输入正误,再用局部匹配反馈错误位置。添加try catch。
特别注意:
对回车、空格等空输入的处理。
作业2——傻瓜式电梯设计
作业重难点总结:
1、电梯类和调度类之间如何巧妙的交互??调度类怎么指挥电梯??
2、调度类怎么才能又快又准的排除同质请求并准备出一个新的请求?
3、如何使ER和FR既有不同又存在可以合并处理的统一性?
4、对队列的操作怎样才能没有BUG?删除同质后下标一定要保持在原地而不是被加一再继续检查!!
5、对同质的准确理解!!抓住ER和FR一定不是同质!
问题代码段1:
1 sliptthenadd代码段
待提升技能点:split在写法上存在很大优化空间,这是因为split封装重用的空间很大,使用了20多个局部位置匹配函数导致对每个字符串的处理都很费时间。split类中根据第一个有效字符是符号还是数字分类,依次将信息存入多项式数组,但if和else的内部存储的过程除下标差1外基本重复,使代码量大幅度增加,给修改带来了很大困难,也增大了出错风险。分工不清,将split和add到队列中的过程设计为了一个方法,检查数据范围的过程重复书写,多个报ERROR的else可以统一设计为1到2个ERROR。
解决方案:将重复的部分封装成一个存储方法,不同的地方可以传入变动信息进行替换,这样只需要调用这个存储函数并传入可变下标即可。分别为分离数据和加入到队列中的过程设计为两个方法,且使得方法对FR和ER指令都有一定的包容性。数字范围检查封装设计。合并多个非法输入的else。
问题代码段2:
将删除同质请求并schedule出一个可执行的请求的方法实现在了请求队列类。
待提升技能点:准备一个新的可执行合法指令的职责属于Scheduler类。请求队列本身只对外提供删除队列元素、查看队列元素、添加队列元素的操作将使得思路更加清晰。
解决方案:将这个自检并调度函数改到Scheduler类。
问题代码段3:
Scheduler类的commander方法将取指令和对电梯发出调度信号一并书写,导致第一条指令和非第一条指令关于调度发出信号的部分重复。
解决方案:将取指令和解析指令发出调度信号分开,其实是否是第一次取指令交给电梯区别不大,可以合并。
虽然这次作业没有被查到功能性BUG,但我认为以下几点值得注意:
1、如果控制指令执行条数是100条,则当使用变量++记录数目并通过判断变量大小决定是否可继续读入时,需要注意边界条件的设计,尤其是取等条件。 2、由于队列的变动幅度比较大,最好采用动态数组,在动态数组中要熟练设计查看、移除、添加元素的方法。 3、属性一律设计为Private,并不是所有的属性都需要对外提供get方法,尽量减少提供get方法的机会,尽量减少甚至杜绝提供set方法,一定要注意减少无意中的变量属性共享,尤其是数组属性。 4、检查输入格式和数字范围过程尽量集中,利于修改。一定要大幅度改进封装水平和抽象水平。
作业3——可捎带(ALS)电梯
作业重难点:
这次作业主要是在理解捎带策略的情况下熟悉对tostring的重写、Scheduler的继承机制、接口的设计与实现等,对代码的重复冗余做了重新的封装优化。Scheduler继承了上次作业,主要继承的是schedule方法,也就是排除同质的方法,同时自己还要补充顺路捎带的调度方法。使用super来调用父类的内容。难点在于如何轻松的在父类和子类之间调用自如,而不是出现混乱。对继承的理解需要借助代码多加观察和练习。
另外,发现大多数同学出现BUG的原因是对捎带的边界条件认识不清。此处墙裂推荐同学们:1、可以提早阅读指导书做到心中有数,但等指导书稳定下来再写代码,否则很可能会带着错误的认识写了一套不合题意的代码然后改的时候你就该哭唧唧了!2、指导书比较长,新建一个文档把重点粘贴下来!做一波面向自己设计需求的重新整理!3、发现自己混乱的时候不是先求助别人而是先重新看指导书再和别人讨论!否则很可能被越说越乱!
由于没有被发现功能性BUG(主要问题是get set有点多说明数据管理分配还有待改善),下面将学习过程中的疑难点做简要总结:
1、重写和重载:
override(重写) 1、方法名、参数、返回值相同。 2、子类方法不能缩小父类方法的访问权限。 3、子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。 4、存在于父类和子类之间。 5、方法被定义为final不能被重写。 overload(重载) 1、参数类型、个数、顺序至少有一个不相同。 2、不能重载只有返回值不同的方法名。 3、存在于父类和子类、同类中。
2、学习继承中一个有趣的现象:
1 public class TestExtend{ 2 public static void main(String args[]){ 3 Student s=new Student(); 4 s.disp(); 5 } 6 } 7 8 class Person{ 9 int a; 10 public Person(){ 11 a=1; 12 } 13 public void disp(){ 14 System.out.println(a); 15 } 16 } 17 18 class Student extends Person{ 19 int a; 20 public Student(){ 21 a=2; 22 } 23 }
解析:运行上面的程序,输出的是1还是2?你会看到输出的是1!
上面的程序中Person和Student类中都有a属性,我们定义了一个Student的对象s,调用s的disp()方法输出的不是Student的a而是Person的a。相信很多人在运行程序前都会觉得应该输出2,但结果告诉我们输出的就是1!子类Student虽然覆盖了父类的属性a,但子类没有重写父类的disp()方法,对象s调用disp()方法时调用的依然是父类的方法,而父类方法访问的依然是父类的a,而不是子类的a。这里或者重写父类的disp()方法,或者将Student中的int a;注释掉才能输出2!其实上面程序在逻辑上是有问题的,既然继承了父类的属性,就不应该在子类中新定义一遍,子类中可以增加属性,但是重写属性没有什么意义! 同时,子类对继承来的属性赋初值时,可以通过调用super(属性初值)也即父类的构造函数的方法。
关于继承的特点的总结:
1、子类只能继承父类所有非私有的成员(成员方法和成员变量) 2、子类不能继承父类的构造方法,但是可以通过super关键字去访问父类的构造方法。
3、我们什么时候考虑继承?如果有两个类A,B。只有他们符合A是B的一种,或者B是A的一种,就可以考虑使用继承
4、重写某方法后子类仍然可以返回父类的方法:使用super
三次作业可能涉及到的一些JAVA易混淆的关键字、特性等的介绍
有关static
static方法是静态方法,没有static的是非静态方法。
静态方法必须创建对象才能访问非静态成员。静态方法可以不创建对象,直接访问静态成员,也可以通过创建对象来访问。
static修饰的静态方法会随着类的定义而被分配和装载入内存中,编译器只为整个类创建了一个静态变量的副本,也就是只分配一个内存空间,虽然可能有多个实例,但这些实例共享该内存,特别值得注意的是,任何一个对象对静态数据成员的修改,都会影响其它对象。
使用类名加前缀访问静态方法,使用实例化对象名访问静态方法。
静态方法只能访问静态数据成员,非静态方法可以访问静态方法和非静态方法,非静态方法可以直接访问非静态数据成员和静态数据成员。
参考代码:
1 import java.util.*; 2 3 public class TestStatic { 4 public static void main(String[]args){ 5 System.out.println(S.getStatic());//使用类名加前缀访问静态方法 6 S s=new S(); 7 System.out.println(s.getStatic());//使用实例化对象名访问静态方法 8 System.out.println(s.get()); 9 } 10 public static class S 11 { 12 private static int a; 13 private int t=0; 14 15 //静态初始器:由static和{}组成,只在类装载的时候(第一次使用类的时候)执行一次,往往用来初始化静态变量。 16 static{ 17 a=10; 18 } 19 20 //静态方法只能访问静态数据成员 21 public static int getStatic() 22 { 23 return a; 24 } 25 26 public int getT() 27 { 28 return t; 29 } 30 31 //非静态方法可以访问静态方法和非静态方法 32 public int get() 33 { 34 getT(); 35 getStatic(); 36 t=a;//非静态方法可以访问非静态数据成员和静态数据成员 37 return t; 38 } 39 } 40 }
super用法总结:
第一、在子类构造方法中要调用父类的构造方法,用“super(参数列表)”的方式调用,参数不是必须的。同时还要注意的一点是:“super(参数列表)”这条语句只能用在子类构造方法体中的第一行。 第二、当子类方法中的局部变量或者子类的成员变量与父类成员变量同名时,也就是子类局部变量覆盖父类成员变量时,用“super.成员变量名”来引用父类成员变量。当然,如果父类的成员变量没有被覆盖,也可以用“super.成员变量名”来引用父类成员变量,不过这是不必要的。 第三、当子类的成员方法覆盖了父类的成员方法时,也就是子类和父类有完全相同的方法定义(但方法体可以不同),此时,用“super.方法名(参数列表)”的方式访问父类的方法。
关于final关键字:
它的主要用法有以下四种:
用来修饰数据,包括成员变量和局部变量,该变量只能被赋值一次且它的值无法被改变。对于成员变量来讲,我们必须在声明时或者构造方法中对它赋值;
用来修饰方法参数,表示在变量的生存期中它的值不能被改变;
修饰方法,表示该方法无法被重写;
修饰类,表示该类无法被继承。
上面的四种方法中,第三种和第四种方法需要谨慎使用,因为在大多数情况下,如果是仅仅为了一点设计上的考虑,我们并不需要使用final来修饰方法和类。
this用法总结:
第一、通过this调用另一个构造方法,用发是this(参数列表),这个仅仅在类的构造方法中,别的地方不能这么用。 第二、函数参数或者函数中的局部变量和成员变量同名的情况下,成员变量被屏蔽,此时要访问成员变量则需要用“this.成员变量名”的方式来引用成员变量。当然,在没有同名的情况下,可以直接用成员变量的名字,而不用this。 第三、在函数中,需要引用该函所属类的当前对象时候,直接用this。 其实这些用法都是从对“this是指向对象本身的一个指针”这句话的更深入的理解而来的。
测试用例设计策略
通常是使用分支树不重不漏的进行测试,主要的测试思想是先整体联合后局部深入,也即先对几个功能进行捆绑性测试,如果发现有问题再进一步细化测试,直到排查出具体错误功能。重点测试一些违反正常思维的情况。
对自己的测试需要先测试输入再测试处理功能,对同学互测的程序需要针对其代码设计猜想其最有可能出现漏洞的地方进行针对性优先测试,主要是先功能后输入,设计针对性的设计样例。
这就涉及到读对方的代码,不要求全部读懂,但要对其处理逻辑心中有数,因为可能他的处理逻辑本身就有漏洞,有必要时可以选用流程图的方式辅助认识其处理运行逻辑。可以结合其公测被测情况设计出公测可能没有测试到的但设计思维相同的样例,比如公测发现其对ER的处理有问题,那么可以优先测试其对FR的相似处理是不是有问题。
对于输入型测试:
主要测试思路为:简单标准型、边界正确型、边界错误型、随机输入型、大规模输入压力测试型
对于功能型测试:
主要测试思路为:基础功能型、不满足处理条件正常退出型、多种被处理情形尤其包括边界情况满足被处理条件的情形。尤其注意一些极端情况的测试和维护。
下面对三次作业的重点测试类型归纳并对经典测试样例举例:
作业1特殊样例:第一个多项式前有无符号、异常字符、空多项式、阶数或系数超大的多项式、单个多项式、负数阶多项式、系数为负的多项式、任意非法输入(包括右大小括号的缺失以及只有一个括号等极端情况的测试)
作业2特殊样例:各种随机输入、1层和10层的FR指令方向特殊性、符号和前导0等、以2的32次方(4字节)为边界的合法和不合法测试、输入时间乱序、同质请求测试(重点),首条指令的目标楼层在1层,多条相同或不同类型的指令连续对同层操作,FR、ER交替发出、同时发出等。
作业3特殊样例:在作业2样例的基础上有意设计捎带的边界样例,尤其是对同层相同时间和不同时间包括开关门阶段及边界的反复操作,以及对某一层的反复请求,注意观察被测程序对同质和选择捎带指令的顺序,因为此处很容易出现逻辑漏洞。以及输出顺序的问题等。
总结
耿直girl需要假装这里有个总结——
总之因为是刚入门,自己的代码即使在没有BUG的情况下也是很需要优化写法的,明显感觉到以下几点需要提起注意(相信也是大多数同学的感受):
1、命名要有意义有区分度。除了临时循环变量不同类之间、不同阶段之间尽量不要出现命名完全一样的变量,很容易蒙圈QAQ。
2、一定要注意封装重用!一定要注意封装重用!一定要注意封装重用!
3、一定要把握好所有的等号边界!!
4、尽量减少private变量的get set方法!交互要简洁!
5、一个功能一次测试,事半功倍!
6、分工一定要准确有道,不可越俎代庖!!文档是好助手!
7、try-catch
8、测试时越不合常规的情况越要好好测!!边界数据使用各种姿势测试很重要!暴力数据也要测!BUG出现在夹缝中!
9、代码修改先不要删,先注释掉!没准是你脑壳瓦特突然改错了!orz
10、一定要学会用eclipse调试,直接打印变量效率很低。
11、readme不要自相矛盾emmm对于自然语言描述难使人理解的地方给出样例说明!
12、在一般的数组和动态数组之间...选动态数组好吗!!动态数组省空间而且简直不能再好用!
13、整理指导书!书读百遍,其义自见。
14、不要害怕学习没用过的东西,java巧妙的地方有很多。百度一下,你就知道。
要是还有没说完的重点或者手残写错的地方emmmmmmmm麻烦大家在评论区提醒下本智障嘻嘻谢= =!我们下期再见!
posted on 2018-04-01 14:37 时常zz的吃货小咸鱼 阅读(490) 评论(4) 编辑 收藏 举报