软件工程-pair work

如果用两个字来形容这次的任务,那一定是"卧槽"

 

结对编程人员

177 吴渊渊

193 薛亚杰

 

照至少一张照片, 展现两人在一起合作编程的情况。

 

 

说明结对编程的优点和缺点。

 

优点:   程序员之间可以互相帮助,得到能力上的提高;

    增强和提高代码的质量,并可以有效的减少BUG;  

    降低学习成本,共享编程经验可以使得代码工作时间大大减少;

    互相讨论问题。更快更有效的解决问题。

缺点:   程序员的磨合需要时间,

 

优点:coder的大部分错误可以在第一时间被reviewer发现,这省下了很多本应当在项目测试阶段花费的时间;

       结对编程写出的每一个程序都体现了两个组员中的较高水平;

              两个人轮流交换角色开发项目,加快项目进展速度;

              两个人结对开发的过程就是两个人互相学习进步的过程。

  缺点:有时候reviewer会整段时间处于无事可做的状态;

              增加了意见统一成本。

结对的每一个人的优点和缺点在哪里 (要列出至少三个优点和一个缺点)。

薛亚杰的优点:努力

      信息检索能力比较强

      代码功底还可以...

薛亚杰的缺点:长期coding导致过于急躁

      面向对象的思想欠缺...写代码一写就是一大坨

 

吴渊渊的优点:认真

      有毅力

      乐于学习新知识

吴渊渊的缺点:代码功底过弱,给对方的工作带来很大的不便(其实没有。。。这是当事人的谦词。。。)

 

 

看教科书和其它资料中关于 Information Hiding, interface design, loose coupling 的章节,说明怎样利用这些好的设计方法。

ASE的设计方法

  信息隐藏:它的基本原则是隐藏代码的复杂性,是提高代码重用性和标准化的基础。使用户不用关心类里面的具体结构,在对象的设计过程中,将对象用于交互的外部信息和只            用于自身实现的内部信息区分开来,实现内部信息的生成和处理过程对其他对象的隐藏,保证对象内部具体实现的改变不会对整体应用造成影响。我们只关注操作的                    方法,而不关注方法是怎么实现的。类与类之间交换信息时,要交流私有变量时,要用事先设计好的方法来访问,例如,我们在其它类里面调用另外一个类的私有变                    量,那么我们必须定义一个获得该类私有变量的方法;要在另一个类里面改变另外一个类里面的变量时,我们也要定义一个改变该类私有变量的方法。在C#里特别方                    便的一点就是有setget,我们可以很方便的定义访问一个类私有变量的方法。

  接口设计:接口可以将类的全部内容升华为抽象,成为子类按照指定行为规范,遵循协议约定来实现接口功能的准则。实际上,接口对抽象类提供了行为规范和行为实现分离的                   绝好机会,使得改写后的抽象类更加符合“自给自足”和“松散耦合”的设计原则。一个好的接口能够提供给后面的程序设计一个良好的框架,在这次电梯调度项目里,接                   口IElevatorIPassengerISchedulerIRequest,我们通过接口能很快的知道电梯、乘客、调度方案、请求都有哪些属性,要实现哪些方法,这样我们的软件测                   试也变得更简单了。

  松散耦合:表示易于维护,易于测试,易于扩展的程度,松耦合值越高,系统就越容易维护。

                  采用类与类之间依赖性低的设计方法,使一个类与另外一个类仿佛隔开了,它们之间只是通过消息来联系的,所以设计一类时,可以不用担心破坏另外一个类。当代                     码有改动时,可以不用大规模的改动我们的代码,使得代码易于维护,我们可以定位于一个出问题的模块,然后对其进行修改,而且能做到不改变其它模块的服务,                     使得代码易于测试。相应的,代码烦人扩展性也可以在一定程度上得到提高。

                  虽然松耦合系统具有很多的好处,但紧耦合系统并非一无是处。如果两个模块在运行过程中需要实时交互信息,并且任何一个模块不能独立工作,那么,就必须选择                     紧耦合模式来构建软件系统。尽管从技术角度上看,松耦合系统具有一定的技术先进性,但并不是所有的软件系统都是松耦合系统。所以,从这个角度来看,选择紧                     耦合系统还是紧耦合系统,取决于软件具体情况和实际需求。

  契约式设计:在调用方法前保证初始条件的正确性。

信息隐藏、接口设计、松耦合都是面向对象设计的重要方法,都是使程序设计时更接近日常认识,在大模块之间关系中不用过于担心细节,只需在模块设计时下功夫。

 

看 Design by Contract, Code Contract 的内容:描述这些做法的优缺点, 说明你是如何把它们融入你的作业中的。

 

一般的观点,在软件体系中,程序库和组件库被类比为server,而使用程序库、组件库的程序被视为client。根据这种C/S关系,我们往往对库程序和组件的质量提出很严苛的要求,强迫它们承担本不应该由它们来承担的责任,而过分纵容client一方,甚至要求库程序去处理明显由于client错误造成的困境。客观上导致程序库和组件库的设计和编写异常困难,而且质量隐患反而更多;同时client一方代码大多松散随意,质量低劣。

而在DbC中,使用者和被调用者地位平等,双方必须彼此履行义务,才可以行驶权利。契约所核查的,是“为保证正确性所必须满足的条件”,因此,当契约被破坏时,只表明一件事:软件系统中有bug。其意义是说,某些条件在到达我这里时,必须已经确保为“真”。谁来确保?应该是系统中的其他模块在先期确保。如果在我这里发现契约没有被遵守,那么表明系统中其他模块没有正确履行自己的义务。所以调用者必须提供正确的参数,被调用者必须保证正确的结果和调用者要求的不变性。双方都有必须履行的义务,也有使用的权利,这样就保证了双方代码的质量,提高了软件工程的效率和质量。

缺点是对于程序语言有一定的要求,契约式编程需要一种机制来验证契约的成立与否。而断言显然是最好的选择,但是并不是所有的程序语言都有断言机制。那么强行使用语言进行模仿就势必造成代码的冗余和不可读性的提高。比如.NET4.0以前就没有assert的概念,在4.0后全面引入了契约式编程的概念,使得契约式编程的可用性大大提高了。此外,契约式编程并未被标准化,因此项目之间的定义和修改各不一样,给代码造成很大混乱,这正是很少在实际中看到契约式编程应用的原因。

在我们的代码中,对于模块间使用了契约的思想,保证双方地位的平等。调用者的传入参数必须是正确的,否则责任不在被调用者,而在传入者。

 

通过截屏显示你是如何用VS 的unit test 来保证你写的类的质量的。显示unit test 对你的写的类(class) 的覆盖率

 

 单元测试这个东西一直不会啊卧槽...这次好不容易实现了一个面向对象的代码,结果好多方法给我蹦出来一个这个啊卧槽...

 

还有好多方法根本不会编写测试代码啊....

 

结果最后只有一个方法能够测试啊...类的覆盖率挫也就是必然的了....

 

不要在意这些细节!(好吧我正在学习。。)

 

画出UML 图显示各个实体之间的关系 (画一个图即可)

 

vs2012中,右键scheduler项目,查看类图,直接生成类图...呵呵呵呵,虽然很挫......

 

不要在意这些细节(大神告诉我是我自己不会弄...)

当然staruml还是王道

说明你的算法的关键 (不必列出源代码), 以及独到之处。

 

扫描每一部电梯,对当前电梯选择最适合的请求

如果电梯处于静止状态(Direction.No):

1.电梯的目标列表不为空,那么选择距离当前楼层最近的楼层前往

2.电梯的目标列表为空,那么从请求队列中选择最合适的前往(何为最合适的:通过实践检验,按照下下,下上,上上,上下的顺序选择)

如果电梯处于上行状态(Direction.Up):

扫描当前楼层与目标楼层之间是否有请求,如果有,那么将其加入电梯的目标列表中,并将电梯的下一个停靠楼层设为所有可以搭顺风车的请求中最接近当前楼层的

如果电梯处于下行状态(Direction.Down):

扫描当前楼层与目标楼层之间是否有请求,如果有,那么将其加入电梯的目标列表中,并将电梯的下一个停靠楼层设为所有可以搭顺风车的请求中最接近当前楼层的

 

算法关键:

 

卧槽..debug了两天半,最后发现问题出现对于QueueReq()这个方法的重写,原来的bus算法因为根本不考虑乘客的请求而在每一层都停,所以它一股脑的把乘客的全部外部请求都压入队列了;而我们的算法需要考虑乘客是否在电梯内,所以这里需要判断乘客的请求类型(RequestType),如果是外部请求(RequestType.DirectionReq),那么将其加入请求列表中;如果是内部请求(RequestType.DestinationReq),说明该乘客已经在电梯内部,那么只需将该请求加入相应电梯对应的目标列表中就好....卧槽卧槽...就这个点debug了两天半啊...我说电梯怎么一直不让人进......

 

独到之处:

 

目前的算法还算可以,对于电梯处于静止状态时他会选择离当前楼层最近的目标楼层前往,如果目标楼层为空那么会选择请求列表中最合适的前往,而如果请求列表为空那么根据样例分析,他会优先前往0层和1层,而如果不为空,那么根据多次测试,他会按照下下,下上,上上,上下的顺序选择目标.

这次的算法只是1.0版本,如果有必要,会进行2.0,3.0版本更高效算法的设计(毕竟要跑得比bus算法还慢基本是不可能了...)

PS:BUS算法和我们的算法跑分表:(工程原始输入文件,不是博客上面的数据要求..)

 

Bus

我们的算法

Passenger1.xml

307.05

87.65

Passenger2.xml

1024.403

443.894

Passenger3.xml

1424.563

215.943

如果换成博客上面要求的电梯容量,那么必然速度会加快好多...运行后发现passenger2.xml可以跑到250左右,passenger3.xml可以跑到180左右

 

Bus算法

我们的算法

Passenger1.xml

307.05

87.65

Passenger2.xml

665.443

261.593

Passenger3.xml

942.943

186.203

 

 

 另外,关于电梯上下班高峰的判断,我的想法是在每一个tick执行queuereq的时候,扫描一下当前准备进入的req,根据req占count的比重来判断是否是上下班高峰;如果req.direction=0|1的比重大于0.8,那么即可判断是上班高峰;如果req.destination=0|1的比重大于0.8(当然这一部分必须是已经进入电梯的req),即可判断是下班高峰.

不过实际执行过程中运行效果反而不如不采用理想...

 

posted @ 2013-10-08 22:55  VeryBigMan  阅读(800)  评论(3编辑  收藏  举报