我的结对编程伙伴是李忠,我是谢伯炎(*****146)
结对编程的优缺点:
(1)首先应该是结对编程的高效率了,结对编程的时候,两个人可以分开做不同的unit,也可以同时做相同的unit。在项目的一些简单的unit,一个人能够很简单的unit就可以分给不同的人去做;对于核心的unit,比如说此次项目电梯调度的算法部分,这是一个核心的部分,需要我们共同讨论,经过讨论后再去实现,或者两个人分别写出自己的想法,用代码实现,这时候,综合两个人效率高的那个人的算法。另外,在结对编程时候,有一定相互监督作用,比起一个写程序,更不会想去玩一些其它的东西。
(2)想法源于两个人的激烈讨论,常常忽然就会有一个灵感突然来袭,或者是会有一些之前不懂得地方,可能一下就懂了。
(3)结对编程的时候乐子多,这样能提高我们的激情,同时也就提高了效率,工作起来很带劲,我们合作的很开心。
(4)在调试的时候,不再是一个人调试时那样无奈了,遇到了bug时,两个人一起,上面那张相片就是我们两个人在调试时候留下的,这时候,有两个人的经验,应付这些bug就能更得心应手一些了。后期维护起来也更加方便。
我的优点:(1)特别的认真;(2)很热情;(3)幽默,跟他一起工作挺好玩的
我的缺点:很喜欢钻牛角尖,项目进度有些慢
李忠的优点:(1)乐观;(2)编码速度比较快;(3)交流能力还行
李忠的缺点:经验比较不足
uml图:
信息隐藏:首先,在类中,定义的变量和方法可以再前面加上一个下划线"_"来标识,这是一个好的命名规范,可以避免无意中对私有成员进行赋值。类与类之间交换信息时,要交流私有变量时,要用事先设计好的方法来访问,这样如果我们在其它类里面调用另外一个类的私有变量,那么我们必须定义一个获得该类私有变量的方法;要在另一个类里面改变另外一个类里面的变量时,我们也要定义一个改变该类私有变量的方法。在C#里特别方便的一点就是有set和get,我们可以很方便的定义访问一个类私有变量的方法。
接口设计:一个好的接口能够提供给后面的程序设计一个良好的框架,在电梯调度项目里,接口IElevator、IPassenger、IScheduler、IRequest,我们通过接口能很快的知道电梯、乘客、调度方案、请求都有哪些属性,要实现哪些方法,而不用关心具体的实现细节;这样我们的软件测试也变得更简单了。
松耦合:在我们的代码设计时,不用担心会破坏其它地方的代码。这种类与类之间依赖性低的设计方法,使一个类与另外一个类仿佛隔开了,它们之间只是通过消息来联系的,所以可以不用担心破坏另外一个类。当代码有改动时,可以不用大规模的改动我们的代码,我们只用更改出问题的模块就好了,而且能做到不改变其它模块的服务。
信息隐藏、接口设计、松耦合都是面向对象设计的重要方法,都是使程序设计时更接近日常认识,在大模块之间关系中不用过于担心细节,只需在模块设计时下功夫。
关于DbC:
契约式编程对于软件工程是一个极大的理论改革,对于C/S模式造成了极大的影响和冲击。对于C/S模式,我们看待两个模块的地位是不平等的,我们往往要求server非常强大,可以处理一切可能的异常,而对client不闻不问,造成了client代码的低劣。
而在DbC中,使用者和被调用者地位平等,双方必须彼此履行义务,才可以行驶权利。调用者必须提供正确的参数,被调用者必须保证正确的结果和调用者要求的不变性。双方都有必须履行的义务,也有使用的权利,这样就保证了双方代码的质量,提高了软件工程的效率和质量。
缺点是对于程序语言有一定的要求,契约式编程需要一种机制来验证契约的成立与否。而断言显然是最好的选择,但是并不是所有的程序语言都有断言机制。那么强行使用语言进行模仿就势必造成代码的冗余和不可读性的提高。比如.NET4.0以前就没有assert的概念,在4.0后全面引入了契约式编程的概念,使得契约式编程的可用性大大提高了。此外,契约式编程并未被标准化,因此项目之间的定义和修改各不一样,给代码造成很大混乱,这正是很少在实际中看到契约式编程应用的原因。
在我们的代码中,对于模块间使用了契约的思想,保证双方地位的平等。调用者的传入参数必须是正确的,否则责任不在被调用者,而在传入者。
我们的算法关键是首先确定电梯的目标点,通过计算选择最能为乘客省时间的方法,而且一旦确定目标点,那么除了"顺路客",我们不做向反方向的运动,保证了电梯不会反复在几个楼层之间运动而浪费时间。而确定目标点则是通过计算,保证接的人的平均时间最短,而且有几个电梯同时空着的时候优先使用近距离的电梯。
我们的算法里,定义了_PassengerQueue专门用于存储乘客发出的方向请求,还定义了一个ArrayList数组_targetOfElev用于存储每个电梯的目标楼层。把每个楼层里发出的方向请求相同的那些请求只存储一个,因为一个乘客如果进入不了一个电梯里的话,那么他就会再发出一次方向请求,这样又会对这个方向请求进行赋值,这样,只要还没有完成将所有的乘客都送到他们要到的楼层,那么_PassengerQueue这个队列就不是空的,那么,电梯调度算法就会继续去完成它。当有乘客进入一个电梯时,就会发出一个目标请求,我们算法里就把这个目标请求加入到数组数组_targetOfElev里该电梯对应的ArrayList里面并且按从大到小排好序,方便后面调用。
在每一个ticks,我们把停靠的电梯和运行中的电梯分开处理:
(1)停靠电梯的处理,这种情形比较多。如果电梯是到达了一个目标楼层后,就在数组_targetOfElev里该电梯对应的ArrayList里面去掉当前电梯所在的楼层。这时候,如果数组_targetOfElev里该电梯对应的ArrayList不为空,就是说电梯的还有目标楼层没有到达,那么就将电梯的下一个目标设为数组_targetOfElev里该电梯对应的ArrayList里面最近的那个目标楼层(这里,向上运行的电梯和向下运行的电梯情况不同);如果数组_targetOfElev里该电梯对应的ArrayList为空,即电梯已经完成了之前数组_targetOfElev里该电梯对应的ArrayList里面的所有任务,那么如果这个时候所有楼层里都没有人发出请求了,那么电梯就往第零层和第一层走,如果有请求,那么电梯就去发出请求的地方接人。
(2)运行电梯的处理,又分为向上运行的电梯和向下运行的电梯,但这是一个对称的过程。如果电梯和电梯目前要前往的目标楼层之间楼层有和电梯运行方向一样的的方向请求时,并且电梯的剩余重量还大于所有人统计平均质量(这里是70)时,就可以使电梯在这一层里停靠一下,接上发出请求的乘客。接上乘客之后,乘客就会发出目标请求,目标请求会加入到数组_targetOfElev里该电梯对应的ArrayList里面。