关于软件工程结对编程作业 PairProject : Elevator Scheduler(电梯调度算法的实现与测试)的总结
1)结对编程队友
1106xxxx 张扬
1106xxxx 杨军
其中,此项目的编程实现主要由前者完成。
2)关于结对编程
结对编程的优点:
- 最直接的一点:在结对编程中,由于有另一个人在你身边和你配合完成同样一件事情的, 所以相对来说你不好意思糊弄,不好意思开小差,更加自觉。
- 结对编程的时候两个人互相审查对方编程时的小错误,相当于随时随地地审查代码,减少错误出现的几率。
- 结对编程无疑会让你更加注意代码的风格和规范,从而能提供更好的设计质量和代码质量,两人合作能有更强的解决问题的能力。
- 结对能更有效地交流,相互学习和传递经验,通过互相取长补短更好地完成任务。
结对编程的缺点:
- 结对编程成员并不总在一起,而且各自的时间安排也并不总是能那么刚好,导致不能够随时沟通,这是个很大的不足。
- 结对编程中两个人有不同的想法,容易造成争执冲突,虽然通过协调可以解决,但有时候并不是那么容易达成一致,容易造成时间上的浪费。
- 结对编程中两人的能力总会有所差别,这会造成进度不一致。
1106xxxx同学的优点:
- 编程技术比较好,想法灵活,能够在结对中给予队友信心。
- 为人友善,在结对中能够团结队友,利于结对的进行。
- 思路清晰,在讨论中能够清晰地发表自己的观点,在结对中为小组贡献了比较大的力量。
缺点:
- 有时候不能完全考虑到所有东西。
1106xxxx同学的优点:
- 为人友善,团结对友,利于结对进行。
- 能虚心听取队友的意见,在结对中各抒己见而又不影响队友的思路。
缺点:
- 编程技术不如队友,拖慢了队友的进度。
3)关于设计方法
信息隐藏(Information Hiding):指在设计和确定模块时,使得一个模块内包含的特定信息(过程或数据),对于不需要这些信息的其他模块来说,是不可访问的。
模块化的设计,使得各个模块之间不能够直接获取信息,而通过相对应的接口类实现模块之间的连接,这样就比较好地保持了代码的信息安全性。在此项目中,信息隐藏设计方法体现在封装性上,通过设计一系列的接口、类等来封装成员,屏蔽一些内部细节,只提供一些必要的成员变量或成员函数给外部,从而达到信息隐藏,提高信息安全。
接口设计(interface design):接口是提供给其他模块或者系统使用的一种约定或者规范。泛指实体把自己提供给外界的一种抽象化物(可以为另一实体),用以由内部操作分离出外部沟通方法,使其能被修改内部而不影响外界其他实体与其交互的方式。
接口的设计一般要满足规范性、相对稳定性、可移植性、安全性、兼容性等特征。在编写程序项目中,使用接口设计方法具有很多的优点,能带来很大的便利。首先,它能够让我们在编程初期定义好主要的模块,设计出一个总体框架,这样在日后就可以根据实际需要具体实现这些接口中的方法,此外还可以在实现接口接口原有方法的基础上进行扩展。由此可见,使用接口设计方法的方便性不言而喻,不仅如此,它还使得程序的逻辑更加清晰、框架更加合理,可读性大大提高。在此电梯调度项目部分源码中,在commons命名空间里定义了IPassenger、IElevator、IScheduler、IRequest四个接口,其他命名空间中主要的类都是通过实现这四个接口来组织的,这就是接口设计方法的运用。
松耦合(loose coupling):耦合性指的是组件之间相互依赖的程度,松耦合就是要求组件之间的依赖程度不要太高,否则对一个组件的修改可能会要求很多其他组件做出相应的变动才能保持正确性,造成“牵一发而动全身”,这是在编程中应该尽量避免的。
面向对象的软件开发和设计的目标之一就是高聚合性和低耦合性。用简单直白的说法,最大聚合就是指类(模块)的封装性要好,功能紧凑而独立;最小耦合就是指类(模块)之间的关联和牵扯越少越好。无耦合是不可能的,理想的是数据耦合(通过接口传递数据),因此在软件设计的过程中设计接口类有利于软件的低耦合性。
上述三种设计方法实际上紧密联系的,信息隐藏和松耦合是好的程序应该具备的特点,而这两者可以通过运用接口设计方法来实现。
4)关于Design by Contract(契约式设计)
契约式设计(DBC)也成为契约式编程,要求软件设计者为软件组件定义正式的,精确的并且可验证的接口,这样就为传统的抽象数据类型增加了先验条件、后验条件和不变式。契约式设计的提出,主要基于软件可靠性方面的考虑。可靠性包括正确性和健壮性,正确性指软件按照需求规格执行的能力,健壮性指软件对需求规格中未声明状况的处理能力。健壮性主要与异常处理机制相关 。正确性一方面包括对象元素内部运行的正确性,另一个重要方面是与其它对象元素交互时的正确性。契约式设计就是要求提供一套机制,在客户程序与提供者之间明确的声明双方的职责与权利,即契约,并能够对这些契约进行验证。
在此项目中,由于给出的源码中已经定义好了各个接口、各种需要用到的数据结构,四个主要接口中的三个也已经实现,我们要做的仅仅是利用已定义好的数据结构、已经实现的类来实现电梯调度这个接口,因此契约式设计方法在此很少用到。
5)单元测试
对自己写的调度算法类进行单元测试。由于初次接触到单元测试,不太懂用,而且该类中各个方法间调用关系较繁杂,测试代码不好编写,导致不是很理想,代码覆盖率较低,以下是测试结果:
6)UML类图
7)关键算法
改写实现新的电梯调度算法 NaiveScheduler:
用数组记录电梯的任务,即电梯需要送乘客去的楼层(升序排列)
1、电梯行驶时:如果电梯在去往目的地途中存在来自电梯外乘客的请求,且乘客要去的方向(上或下)与电梯当前行进方向一致且能容得下,则接受请求,顺路带人
2、电梯停止时:
(1)让要到这一层的乘客下电梯,从任务数组中删去这一楼层
(2)若电梯还有任务,则继续去执行任务(按停靠前的行进方向行进即可)
(3)若电梯已无任务,即电梯里已经没有人,则看是否有外部请求,即看是否需要去 ”接客“:
A:若没有外部请求,则电梯静止不动,不用去 “接客”
B:若有外部请求,则进行如下操作:
a:若是上班高峰,则让这三个电梯直接去0层,留一个在上面执行任务;
b:否则以电梯当前楼层为参照楼层,按如下优先策略(优先级依次递减) “接客” :
1)在下面且想下楼的,选择距离电梯最近的请求(下下)
2)在下面且想上楼的,选择距离电梯最远的请求(下上)
3)在上面且想上楼的,选择距离电梯最近的请求(上上)
4)在上面且想下楼的,选择距离电梯最远的请求(上下)
选择这个优先级基于两点考虑:其一,尽量先响应下面的请求,因为高峰期0层和1层的客流量最大
其二,乘客想去的楼层相对于乘客所在楼层的方向尽量和电梯去接他们时的行进方向相同
算法的独到之处:经过与同学们的交流得知大家的优先级基本都是如上所述的那样,算法也总体相同。此算法的独到之处在于对上班高峰的优化:上班高峰时有80%客流量是从0或1层去往其它层,而20%是正常的客流量。这里让三个电梯直接去0层,留一个按正常情况运行。经测试发现,与没有此优化相比,效率有了不少的提高.
用passenger2.xml进行测试,运行结果对比如下: