答辩评分标准明细
项目报告评价及答辩评分 | ||||||||||||
班级 | 学号 | 姓名 | ||||||||||
功能 | 功能 序号 | 目标 分值 | 评价依据 | 评价 意见 | 得分 | |||||||
项目报告 | 1 (20分) | 1.1 | 5 | 报告中对为什么选择这种设计模式来处理此问题的分析描述是否准确? | ||||||||
1.2 | 5 | 报告中对建模过程描述是否恰当?对UML中各个角色的含义描述是否符合题意?对建模后的解决方案在满足基本需求的前提下具有最佳的可扩展性的描述是否准确? | ||||||||||
1.3 | 10 | 程序是否较好地按要求完成各功能的实现?各个角色类的设计是否正确? | ||||||||||
2 (20分) | 2.1 | 5 | 报告中对为什么选择这种设计模式来处理此问题的分析描述是否准确? | |||||||||
2.2 | 5 | 报告中对建模过程描述是否恰当?对UML中各个角色的含义描述是否符合题意?对建模后的解决方案在满足基本需求的前提下具有最佳的可扩展性的描述是否准确? | ||||||||||
2.3 | 10 | 程序是否较好地按要求完成各功能的实现?各个角色类的设计是否正确? | ||||||||||
3 (20分) | 3.1 | 5 | 报告中对为什么选择这种设计模式来处理此问题的分析描述是否准确? | |||||||||
3.2 | 5 | 报告中对建模过程描述是否恰当?对UML中各个角色的含义描述是否符合题意?对建模后的解决方案在满足基本需求的前提下具有最佳的可扩展性的描述是否准确? | ||||||||||
3.3 | 10 | 程序是否较好地按要求完成各功能的实现?各个角色类的设计是否正确? | ||||||||||
4 (20分) | 4.1 | 10 | MVC各个角色的含义描述是否准确?本系统设计设计的组件中M、V、C各是哪些描述是否清楚? | |||||||||
4.2 | 10 | 各功能模块设计与实现(包括前端、控制层、模型层)描述是否清楚?运行效果情况如何? | ||||||||||
项目答辩 | 答辩内容 | 分值 | 评价依据 | 评价 意见 | 得分 | |||||||
系统运行演示 | 5 | 系统是否能够正常运行,是否实现所要求的各项功能? | ||||||||||
设计模式应用 | 10 | 对设计中使用的设计模式是否能正确解释其原理及应用场景?是否能说明采用对应模式的缘由?系统是否符合面向对象设计原则? | ||||||||||
体系结构应用 | 5 | 能否正确理解设计中所使用的的体系结构及采用该模式的优缺点? | ||||||||||
项目报告得分 | 答辩得分 | 总分 |
项目效果展示
本项目由 杨哥 大力支持
微信小程序前端:
服务/统计后台:
1、餐厅菜品信息显示模块的设计与实现
要求在不暴露每种数据集内部结构的同时,可以让外部代码透明地访问其中包含的元素,系统模块要有较好的可扩展性。请根据题意采用某种设计模式,使用图文的方式显示各类商品信息,实现首页、上一页、下一页和最后一页的功能。请在实现过程明确所使用的设计模式并说明使用的原因及合理性。
1.1 选择适当的面向对象设计模式
根据题意,要完成此功能应该采用迭代器设计模式来处理
迭代器模式定义:提供一种方法顺序访问一个聚合对象中各个元素,且不用暴露该对象的内部表示。
所谓“迭代”,就是按照一定的次序或顺序进行重复操作,这个操作可以是遍历也可以是反复的计算,而迭代器就是按照一定的顺序对元素进行遍历的过程。为何用一个迭代器遍历代替for循环呢?这就涉及到软件设计中最重要的一个原则——高内聚,低耦合。
for循环遍历操作时,代码中有着大量的耦合,当我们需要修改代码的时候,不能做到少改甚至不改遍历的代码,而迭代器可以做到,这为代码的可移植性、可扩展性等特性奠定了基础。而那个重复操作就有页面的翻动,同类信息的陈列/展示等。故而采用了迭代器设计模式。
这样似乎是把简单的问题给搞复杂了,但是这种复杂恰恰是为了以后设计和扩展的简单。正如没有规划的盖一座房子,很快就盖成了一座房子,可是因为没有考虑到房子的方位、地基、以后的扩展、居住的舒适,改出来的房子最后不能进行扩展并且不符合力学的美感和力感,最终只能重新拆掉重建。
迭代器的种类非常多,我们可以根据遍历的次序进行设计,来实现相应的功能。从该设计模式中我们可以看到接口的应用,面向接口编程的概念,以及元素的遍历与实现分离,实现了高内聚和低耦合。优点:解耦迭代与聚集,迭代器的变化不会影响容器;缺点:对于比较简单的遍历,使用迭代器方式遍历较为繁琐;
1.2 UML类图的设计和绘制
该设计模式的主要角色有:
聚合类(Aggregate Classes):图文<-->各类商品信息的集合
迭代器(Iterator):操作按钮<-->对各类商品信息的图文进行操作
容器/聚类对象:$aggregate、$current
抽象的容器:Aggregate
具体的容器:$items = array()
具体的迭代器:MineIterator
迭代器标准(MyIterator):first()、next()、isDone()、currentItem()、currentIdx()
我选设计了具体的容器适配具体的迭代器。在我的迭代器标准中放入取得第一个元素的方法first(),取得下一个元素的方法next(),判断是否遍历结束的方法isDone(),移出当前对象的方法remove()等方法。
迭代器模式的UML类图
1.3 该功能的实现
在index.js中,我使用了生命周期函数监听页面加载。在封装的data.list集合中,当加载数据成功且last_id为0时,建立数据列表,否则反馈失败信息给微信小程序,不显示加载。实现了在不使用for循环的情况下完成循环遍历操作。
2、点餐订单生成模块的设计与实现
客户选中某菜品后需要再选择不同口味,要求系统会根据菜品和口味选择的不同进行价格计算。但由于种类和口味会有变化(如添加新菜品或口味),在程序设计时请根据题意采用某种设计模式,使得设计的软件系统具有较好的扩展性和可维护性。
2.1 选择适当的面向对象设计模式
根据题意,要完成此功能应该采用装饰器设计模式来处理
装饰器设计模式定义:在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
装饰器模式是为了运行时动态的扩展一个类的功能。它谨循开闭原则,它实现的关键是继承和组合的结合使用,解耦对象之间的关系。装饰器模式充分展示了组合的灵活。利用它来实现扩展。它同时也是开闭原则的体现。 如果对某个类实现运行时功能动态的扩展, 这个时候就可以考虑使用装饰器模式。
装饰器模式的职责就是动态地给一个对象添加一些额外的职责(菜品有基本的属性,我们要赋予它额外的特性作为区分)。就增加功能来说,Decorator模式相比生成子类更为灵活。该模式以对客户端透明的方式扩展对象的功能。
装饰器模式可以动态的添加修改类的功能,抽象类提供了一项功能,如果要在修改并添加额外的功能,传统的编程是写一个子类去继承它,并重新实现类的方法,使用装饰器模式,仅需在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性
这样的情况下,如果为某一个对象添加特性,就比如我在我的设计中,设计了12种不同口味的奶茶,他们的基本属性都是饮品,我可以根据实际的需要,推出新季产品,也就是添加新菜品,在淡季的时候再撤销这个特性,这时要保证不会对其他的奶茶(对象)产生影响,还要很方便地让我们进行透明的操作。就很符合装饰器模式的特点。
因为装饰器模式的适用环境就是:
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
- 处理那些可以撤消的职责。
- 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。缺点:多层装饰比较复杂。
2.2 UML类图的设计和绘制
该设计模式的主要角色有:
抽象的被装饰角色:奶茶、粥、小炒、主食等。
具体的被装饰角色,继承对应的抽象的被装饰角色的属性:
拿养乐多来说就是:大小杯的芒果养乐多、葡萄柚养乐多、绿茶养乐多...
拿粥来说就是:红豆薏米粥、枸杞酒酿玉米羹、红豆桂圆银耳羹...
拿小炒来说就是:蚝油青菜小炒(大小份)、鸡蛋木耳小炒(大小份)、可乐鸡翅...
拿主食来说就是:奶香糯玉米松饼、红糖酥饼。
本题待设计的角色是:西餐
下图以奶茶的UML类图为例说明装饰器模式的使用:
装饰器模式的一个UML类图
2.3 该功能的实现
对于装饰器模式,它的实现一般如下:
抽象的被装饰角色(所有的角色都要直接或间接的实现本角色)
具体的被装饰角色,实现或继承a(被功能扩展的角色)
装饰角色,实现或继承a(本类有对a的引用,所有的具体装饰角色都需要继承这个角
多个具体修饰角色,继承c(对被装饰角色的功能扩展,可以任意搭配使用)
而在我自己对应的实现当中:
点餐订单的生成统计以及价格统计系列功能放在了SHOP/api/controller/Food.php下。当选中大的系列菜品后,可以进行细致的选择,实现精准的定位,并且能够根据顾客的口味偏好选择不同风味的产品、根据食量选择不同分量的食物,具备较好的合理性、逻辑性,符合人性化点餐。
比如:当我渴了的时候,可以点击奶茶,选择大杯或中杯珍珠奶茶进行下单。对应的抽象的被装饰角色就是美食,所有的角色都要直接或间接的实现本角色;具体的被装饰角色就是饮品,继承了美食的属性;装饰角色就是奶茶,对饮品有所引用且所有的具体装饰角色都继承这个角色;多个具体装饰角色就是珍珠奶茶、鲜芋奶茶、布丁奶茶,对装饰角色进行了功能扩展。并且还可以选择大小份对多个具体装饰角色进行装饰。
价格计算
3、销售统计功能模块的设计与实现
由于统计类型不同,如:按日期范围、按菜品类型、销量和偏好等统计方式。这就要求统计具有多样性灵活性,而且未来可能增加其它处理方式,要求容易地扩展出其它导出格式。同时为了降低销售统计模块与上一层的耦合关系,请根据题意采用合适的设计模式完成此任务,并在实现过程明确所使用的设计模式并说明使用的原因及合理性。
3.1 选择适当的面向对象设计模式
根据题意,要完成此功能应该采用工厂设计模式来处理
定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。
工厂设计模式的角色有:
抽象工厂(Creator)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
具体工厂(Concrete Creator)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。在上图中有两个这样的角色:BulbCreator与TubeCreator。
抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。在上图中,这个角色是Light。
具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。
工厂模式的核心本质是:实例化对象不使用new,用工厂方法创建对象;使用工厂统一管理对象的创建,将调用者跟实现类解耦。
优点:工厂方法模式是为了克服简单工厂模式的缺点(主要为了满足OCP)而设计出来。简单工厂模式的工厂类随着产品类的增加需要增加很多方法/代码),工厂方法模式每个具体工厂类只完成单一任务,代码简洁。工厂方法模式完全满足OCP,有非常良好的扩展性。
缺点:假如某个具体产品类需要进行一定的修改,很可能需要修改对应的工厂类。当同时需要修改多个产品类的时候,对工厂类的修改会变得相当麻烦。比如说,每增加一个产品,相应的也要增加一个子工厂,会加大了额外的开发量。
3.2 UML类图的设计和绘制
工厂方法模式的一个UML类图
3.3 该功能的实现
订单统计
4、基于MVC模式的餐厅自助点餐系统的设计与实现
4.1 MVC设计模式在本系统中的体现
(1)MVC各个组件的含义
M:Model数据模型层,负责数据操作它代表一个存取数据的对象。它也可以带有逻辑,在数据变化时更新控制器,如:Bean类,Flavour类。
V:View视图层,负责显示视图,它代表模型包含的数据的可视化。
C:Controller控制器,实现业务逻辑。它作用于模型和视图上,控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。
4.2 餐厅菜品信息显示功能的设计与实现
(1)前端设计(View层)
(2)控制层设计(Controller层)
(3)模型层设计(Model层)
4.3 点餐订单生成模块的设计与实现
(1)前端设计(View层)
(2)控制层设计(Controller层)
(3)模型层设计(Model层)
4.4 销售统计功能模块的设计与实现
(1)前端设计(View层)
(2)控制层设计(Controller层)
(3)模型层设计(Model层)
5、项目设计小结
设计模式是面向对象编程的热门话题之一,越来越多的开发人员认识到设计模式的重要性。采用各种语言实现设计模式的文章也越来越多,但是很多开发人员发现很难将设计模式与实际开发中需要解决的具体问题相联系。因为使用设计模式的难点往往不在于模式的实现,而在于很难确定哪种模式可以在现实的应用场景中采用,从而导致了在现实的项目中,面对客户的压力,我们总是采用最直截了当的方法解决问题,来不及多考虑这些方法的优劣,即使明知将带来更大的麻烦也必须如此。有些时候因为选择了不恰当的设计模式,使原本简单的问题变得复杂化。
在我编码的过程中,遇到的问题有很多。不够优雅的代码、过于僵硬的设计,等等,下面我将通过如上两个例子讨论
1. 解决过多的if…else判断问题
如果在一段代码中,不少地方需根据某类型或状态等做出不同的处理,那当类型或状态增加时,这些代码将会过于僵硬,扩展性差,只有在各个分布了if…else的再增加一个else if,可维护性可想而知。设计模式中有一种模式可以解决该问题,即状态模式。状态模式给我们带来的好处如下:
1) 状态模式需要对每一个对每一个系统可能取得的状态创立一个状态类(State)的子类,当系统的状态变化时,系统改变所选的子类。与一个特定的状态有关的行为都被包装在一个特定的对象里,而且当需要增加新的状态时,可以以子类的方式将它加到系统里,从而提高了易维护性和可扩展性;
2)由于每一个状态都被包装到了类里面,避免了使用过多的条件转移语句。
2.解决过度资源损耗问题
在该例中,每次通过get方法获取某属性时,都会重新载入文件中的所有内容,造成资源的不必要损耗。该设计模式中,对于此种情况,可以通过单例(Singleton)模式来优化处理。