1.1结对编程的优缺点
结对编程相对于个人编程有很多优点。
首先,督促作用,在讨论过程中能够很快投入工作,为了不耽误对方时间,我们会尽快完成各自的任务;
第二,节约时间,相互交流,能够更快的确定算法方案,比起一个人苦思冥想要来的快得多;
第三,提高效率,一些简单的unit,一个人能够很简单的完成就可以分给不同的人去做;对于核心的unit,比如说此次项目电梯调度的算法部分,这是一个核心的部分,需要我们共同讨论,经过讨论后确定较优的方案再去实现;或者在遇到bug时,经过讨论可以更加迅速的有效解决问题;
第四,降低学习成本,读代码是两个人一起看的,有不会的地方随时可以相互询问讨论,学到了新的东西,增进对已有知识的掌握,还能学到一些好的编程习惯。
结对编程缺点:
1.2团队成员的优缺点
首先是宋天舒同学,他是个精明能干,待人真诚的人,编程能力较强。缺点是有时候急于求成,不等助教写完代码就开始了。
1.3我们的合作流程
我的合作是这样进行的:
1、 拿到题目,两个人在一起读题目,挖掘题目信息;
2、 共同读代码,写注释,遇到疑问及时讨论或上网查询;
3、 针对电梯调度算法各自提出看法,讨论,模拟并确定算法;
4、 在实际编码中,发现最初讨论的算法并不是很好实现,通过现场沟通,修改算法,修改代码;
5、 一起对代码进行测试和优化;
8、 对电梯调度算法的表现基本满意;
9、 开始写UI,UI比想象中的难写多了……
10、写博客
Information Hiding:信息隐藏指的是在设计模块时将某些特定的信息,包括属性或方法隐藏起来,对于不需要这些信息的其他类来说是不可访问的。信息隐藏提高了数据的安全性,避免了信息在无关的其他地方被非法更改,也有益于程序模块化的设计。
在编程过程中,运用信息隐藏技术需要我们对各模块的数据和方法在整个程序中的作用有着比较深的理解,在多层设计中的层与层之间加入接口层;其次,所有类与类之间都通过接口类访问;同时,类的所有数据成员都是private,所有访问都是通过访问函数实现的。
Interface design:接口是把公共的非静态方法和属性组合起来,以封装特定功能的一个集合。
接口就是契约。实际工程中,当我们遇到模块中一些固定的特定功能时,我们可以把这些功能封装成接口。通过接口可以使其他的工程人员能够很快知道电梯、乘客、调度方案、请求等对象所具有的属性和需要实现的方法,而不必关心具体的实现细节。
Loose Coupling:耦合指的是一个元素对另一元素的直接了解程度。松散耦合是在一个系统中使各组件互相连接的方法,使这些模块在最小的可行范围内彼此依赖。松耦合架构可以降低整体复杂性和依赖性,每个模块具有各自的独立性,仅通过消息来传递信息,修改其中的某个模块并不会对其他模块造成破坏,方便我们对不同的模块的修改和管理。
在软件工程中,为了避免模块之间产生过多的联系以免产生不必要甚至危险的牵连,我们应该尽量使各模块的信息尽量完整与独立,从而简化测试,减少风险。
1.5关于Design by Contract:
契约式设计是一种设计计算机软件的方法。这种方法要求软件设计者为软件组件定义正式的,精确的并且可验证的接口,这样,为传统的抽象数据类型又增加了先验条件、后验条件和不变式。其中前置条件指的是为了调用函数,必须为真的条件,在其违反时,函数决不调用,传递好数据时调用者的责任;后置条件指的是函数保证能做到的事情,函数完成式的状态,函数有这一事实表示它会结束,不会无休止的循环;不变式指的是从调用者的角度来看,该条件总是为真,在函数的内部处理过程中,不变式可以为变,但在函数结束后,控制返回调用者时,不变式必须为真。
如果在面向对象中一个类的函数提供了某种功能,那么它要:
- 期望所有调用它的客户模块都保证一定的进入条件:这就是函数的先验条件—客户的义务和供应商的权利,这样它就不用去处理不满足先验条件的情况。
- 保证退出时给出特定的属性:这就是函数的后验条件—供应商的义务,显然也是客户的权利。
- 在进入时假定,并在退出时保持一些特定的属性:不变式。
优点:
契约能使文档更出色;契约是类特性的公开视图中的固有成分;
有着更可靠的文档,运行时要检查断言,以便保证制定的契约与程序的实际运行情况一致;
断言定义了测试的预期结果,并且由代码进行维护,使程序有明确的测试指导;
既能够获得精确规范得到的益处,同时还使得程序员继续以他们所熟悉的方式工作。
缺点:
断言不能沿着继承层次往下遗传。如果你重新定义了某个具有合约的基类方法,实现该合约的的断言不会被正确调用,你必须手工调类不变式,基本的合约不会主动实现。
1.6Code Contract
程序代码合约是.NET Framework 4.0的新功能,它是微软对契约式编程(Design by contract)概念所提出的一种解决方案,主要由前置条件(Preconditions)、后置条件(Postconditions)、与对象不变式(Object Invariants)这三大契约所构成,可以很容易的为程序代码加入验证程序代码,降低程序的错误发生率,提高程序的质量,也可以整合单元测试,减少单元测试的工作量,甚至整合文档管理器,让产出的程序文件更为详细 。
使用Code Contracts主要可让我们享有下列四项特点:
1、提升自动测试程度
2、静态验证
3、执行阶段验证
4、文件产生
在我们的代码中,对于模块间使用了契约的思想,保证双方地位的平等。有必要的话会在方法的注释中书写不变式和前置条件,从而保证调用者的传入参数必须是正确的。同时在进行单元测试的时候,对有前置条件和不变式的方法也进行了必要的验证:即对象有效性和方法实现正确性推理,从而保证在对象状态满足不变式的前提下,所有方法实现都满足规格(契约)。
1.7Unit Test
除了私有方法无法进行测试以外,还是可以比较全面的覆盖代码块的...
也可以看到各个模块的覆盖率还是比较可观的
特别是scheduler,由于私有方法Run()和IsAtBottomFloor(),IsAtTopFloor()无法测试拉低了整体覆盖率,覆盖的还是比较全面的...
测试函数还是蛮难写的,比如为了覆盖GetTargetReq方法全部块写的测试函数约有100多行汗..
1.8UML
简略图如下:
由于详细信息过多:故再截个稍微复杂的图
1.9算法的独到之处
我们的算法里,每个电梯内部都给了一个电梯调度子程序,同时定义了_dstPassengerQueue专门用于存储乘客发出的楼层请求,对于每一个进入该电梯的乘客都将其生成的楼层请求入队。通过判断该队列是否为空分为;两种情况来判断:
电梯内有乘客:如果电梯还没有满员或满载,那么在同方向上楼层选取请求,电梯下一个目标是最近的顺路方向请求或者在_dstPassengerQueue中的最近的目的地(楼层请求);
否则将目标楼层设置成楼层请求队列中的下一个最近的乘客目的地楼层。
电梯内没有乘客:判断方向是否和当前电梯的HistoryDirection分成四个优先级,先在处于同方向上到顶(底)的所有楼层上的所有方向请求中选取,优先去同方向最近的方向请求,其次选择反方向最远的方向请求,然后在反方向上到顶(底)的所有楼层上的所有方向请求中选取,优先去同反方向最近的方向请求,其次选择同方向最远的方向请求。
[附加题]
2.1改进电梯调度的interface 设计, 让它更好地反映现实, 更能让学生练习算法, 更好地实现信息隐藏和信息共享。
1、给每个电梯加一个目标楼层的动态数组。即我们程序中的_Target。
2、在阅读代码中,我们发现电梯关上需要5ticks,太慢了。应该在电梯里加一个可以快速关闭的按钮,并提供接口。
3、给人一个进电梯的速度,高峰期时进电梯时间必然增长,不能都视为一样。
4、在3的基础上,增加一个电梯延时关闭的接口。
2.2设计UI界面, 显示乘客/电梯的运动, 并实现之。
时间很紧,用.NET开发一个不停刷新的窗口这个事情有点像写Java游戏,但是还要显示别的信息,实时更新。没干过,指不定出多少问题。于是我们计划计划设计一步,实现一步,看最后能多到什么程度。
设计1、首先基本功能是要模拟电梯运行的过程,并实时显示对应的ticks
设计2、提供设置配置文件的按钮和对话框
使用C#的winform编写,通过不同的Label的移动展现电梯的状态;通过Label上显示的内容表示电梯信息。
程序包括两个线程,UI线程与电梯调度算法所在的线程.
一个线程运行主程序,一个线程在每一个tick刷新UI界面。
原本想加背景图片的,迫于这样刷新界面的过程会变卡,最终去了..
两个按钮分别用来设置配置文件,配置成功点开始开始模拟电梯运行
运行完成显示最终乘客平均用时结果并提示信息:
2.3阅读有关 MVC 和 MVVM 设计模式的文章。说明你写的电梯调度的UI /Algorithm/interface 如何实现了MVC 或MVVM 的算法。
在阅读了MVC和MVVM的相关文章和百度介绍后,我们了解到:
MVC是一个框架模式,它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件:模型、视图、控制器;M是指业务模型,V是指用户界面,C则是控制器。它们各自处理自己的任务。最典型的MVC就是JSP + servlet + javabean的模式。而MVVM(Model-View-ViewModel)框架的由来便是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架。
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大优点
1. 低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
2. 可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
3. 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xaml代码。
4. 可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。
在我们的调度算法里主要实现了MVC模式,即将输入输出和处理分开。Scheduler的调度主算法就是负责处理部分,处理电梯的运行和调度,而输如完全由Loader完成,输出完全由Elevator,SigmaPasenger和World完成。