目录
前言
本次题目集以航空运送货物为背景,设计航空货物管理系统,主要考察对类设计的把握是否合理还有对继承和多态的使用,能否设计出符合标准的类,是否充分理解对面向对象六大设计原则(SRP,OCP,LSP,DIP,CRP,LOD),设计出的类是否能够遵循这六大原则。
1.关于知识点
- 运用六大设计原则设计出合理的类,准确把握类与类之间的关系。
- 继承与多态的灵活使用。
- 抽象类与抽象方法。
2.关于题量
- 两次题集题量均不多只有三道题,对两次题集的最后一题进行迭代。
3.关于难度
- 难度不大,最后一题题目内容稍长,但容易理解。
设计与分析
第一次作业
本次题目模拟某客户到该航空公司办理一次货运业务的过程:
航空公司提供如下信息:
- 航班信息(航班号,航班起飞机场所在城市,航班降落机场所在城市,航班
日期,航班最大载重量)
客户填写货运订单并进行支付,需要提供如下信息:
- 客户信息(姓名,电话号码等)
- 货物信息(货物名称,货物包装长、宽、高尺寸,货物重量等)
- 运送信息(发件人姓名、电话、地址,收件人姓名、电话、地址,所选航班号,订单日期)
- 支付方式(支付宝支付、微信支付)
一个货运订单可以运送多件货物,每件货物均需要根据重量及费率单独
计费。
我的设计
- 题目分析:
- 题目中有客户、发件人、收件人、货物、支付方式、航班等并且是在模拟客户在航空公式办理业务的过程
- 将现实转化为抽象的类,进行类设计:

- 类与类之间好比大树生出支再生出叶子,错综复杂,又很清晰,所以我们要从末尾(叶)开始设计类,关系越少,职责清晰。
- 针对货物:题目中的货物有长宽高等属性,但是不是所有的货物都有长宽高,比如球或者不规则物体,所以我把货物做成了一个抽象类,下面继承了一个长方体货物。
- 针对支付方式:支付方式有微信支付、支付宝支付、明显需要采用继承=,将支付做成抽象类,下面继承两种支付方式,使用原因有:遵循开闭原则,如果还要加现金支付,不需要修改原来代码,能够使用多态,无论是什么支付都能通过父类进行操作,减少了条件判断和类型转换的代码,减少代码的重复。
- 针对发件人与收件人:我最开始的想法是把收发件人和客户继承同一个父类因为有很多相似的属性,转念一想,是客户办理业务,继承同一个父类耦合是不是太强了,最终我还是把收发件人做成一个单独的类。
- 因为要处理客户的业务,好比我们在手机上买东西,比如淘宝,都有订单,客户买东西就是在下订单,为了减小耦合设计合理符合实际,把订单类拆分成两个,一个订单项类(OrderItem),一个订单类(Order),订单与订单类之间聚合,遵循合成复用。
- 最后为了处理客户与订单之间的业务逻辑,设置一个中间类Controll,好比买房卖房需要中介,减小耦合,遵循单一职责原则。
- 设计了一个接口:针对运费规则设置了一个接口,避免运费规则改变修改代码,遵循开闭原则。
- 类中关键方法的设计:
- 在货物类中设计了一个计算货物体积重量的方法,该方法为抽象方法子类长方体货物对其复写,因为考虑到不同类型的货物体积计算不一样。
java
public void setVolumeWight(double volumeWight) {
this.volumeWeight = volumeWight;
}
- 在订单项中设计求货物价格的方法,通过该货物计费率(依赖费率接口)和货物重量求出价格,还有计算计费重量方法,通过比较体积重量和实际重量大小返回较大值。
java
public double getItemSum(ChargingRate chargingRate){
double wight=chargeableWeight();
return chargingRate.calculateChargingRate(wight)*wight;
}
- 在订单类中有计算货物总质量和总价格方法,计算总重量是为了确认该订单能否运输(有无超过飞机剩余承受重量),计算总价格方便支付。
java
public double getWightSum() {
double sum=0;
for(OrderItem orderItem:orderItems){
sum += orderItem.chargeableWeight();
}
return sum;
}
- 在控制类中有查询订单报表 、查询货物报表、增加订单方法。通过控制类进行订单的增加降低解耦性。
java
//增加订单
public void addOrder(int id,String time,ArrayList<OrderItem> orderItems,String name,String phone,TransportInformation transportInformation){
Order order=new Order(id,time,orderItems,name,phone,transportInformation);
orders.add(order);
}
- 在客户类中有一个下订单的方法,通过控制类来实现。
java
//客户下订单
public void addOrder(int id,String time,ArrayList<OrderItem> orderItems,TransportInformation transportInformation){
orderManage.addOrder(id,time,orderItems,this.name,this.phone,transportInformation);
}
我的分析
1.类图
对类设计进行分析:
- 长方体货物类(CuboidProduct)继承自货物类(Product),增强扩展性,符合开闭原则。
- 订单项类依赖于抽象的货物类,依赖于于抽象不依赖于具体符合依赖倒转原则。
- 订单项类依赖于接口,类图中有所差错。
- 订单类于订单项类聚合,符合合成服用原则,减少重复代码。
- 订单类依赖于抽象类支付类(Payment),支付类下面继承两个类(微信,支付宝),实现了多态,符合依赖倒转原则、开闭原则、里氏代换原则。
- 运送信息类依赖于航班类、收发件人类,再与订单类依赖,这里应该使用聚合实现代码复用,图中有所差错。
- 客户关联控制类,控制类关联订单类,减少耦合,符合单一职责,迪米特法则。
2.SourceMontor生成表:
对代码进行分析:
- 注释率太低:再代码中没有足够的注释,只有在一些关键性的地方增加注释,导致注释率偏低,要有良好的注释习惯。
- 平均复杂度偏低:某些方法可能过于简单,但是一个方法不能承担过多职责,增强复用,所以问题不大。
- 其他如平均深度、最大复杂度等在合理范围。
第二次作业
第二次为第一次的迭代,较上一次增加如下需求:
-货物类型分为普通货物、危险货物和加急货物三种。
-三种货物费率不同。
-支付方式增加了现金支付。
-客户分为个人用户和集团用户,个人用户9折优惠,集团用户8折优惠。
我的设计
1.题目分析:
题目较上一次增加了客户种类,需要把客户做出抽象类,然后继承下来,增加折扣率,需新增折扣率接口。
2.类设计:
-对于货物类在上次题目中我已经把货物做成抽象类,只不过货物类型方向不一样,我是按货物的形状分类,题目则按货物种类,差别不大。
-对于支付类,上次题目中已经形成了明确的继承关系,新增的现金支付只需要继承下来就好了,开闭原则。
-对于客户类则要重新设计,把客户做成抽象类然后继承下来两种客户类型。
-对于新增的折扣率将它做成接口,实现两种费率模式,利用多态来具体施行操作。
-新增的货物费率则是在原来的接口上再继承两种费率模式下来。
3.方法设计上:
在某些方法上增加形参折扣率的接口如订单项中求总费用,其他逻辑未改变。
我的分析
1.类图:

类设计分析:
较于第一次题目的改变与增加
- 对于飞机类、收发件人类改为与运送信息进行聚合,更加合理,符合合成复用原则。
- 订单类新增依赖折扣率接口,符合依赖倒转原则。
- 客户类变成抽象类,个人用户和集团用户继承自客户类,符合开闭原则。
2.SourceMontor生成表:

对代码分析:
-注释率偏低:代码中缺少足够的注释,不利于理解。
-最大复杂度过高:可能某个方法承担过多职责,需要合理拆分。
-其他均在正常范围内,较为合理,如:方法数量、类数量、最大深度等。
踩坑心得
第一次作业
- 第一次作业中代码第一次提交,竟然全错误,然来发现要输出的是计费重量而不是物体的实际重量,因为示例的计费重量和实际重量相等则未发现。
- 刚开始拿到题目一直在研究如何设计类,想过很多方式,最开始是通过控制类来调用输出,和客户没有直接关系,客户里面也没有下订单的方法,由于题目背景为客户办理业务,所以还是觉得不妥,进行了修改,客户有下订单的方法,通过客户(客户调用控制类)来增加订单。
- 还有由于题目要进行迭代,并不知道下一步迭代的方向是什么,尽可能的设计更加合理,减少第二次题目对代码的修改,所以我把原来的货物类做成抽象类,继承下来一个长方体类,适合扩展。
- 对于运送信息类,最开始是没有这个类的,航班、收发件人类直接与订单类进行依赖,后来觉得他们有共性,把他们再包装成运输信息类,在与订单类依赖。
第二次作业
- 第二次作业在第一次作业的基础上进行迭代,虽然第一次有在为第二次做准备,但计划赶不上变化,如没想到客户类也要做成抽象类,不同的客户种类还有相应的折扣率,虽然货物类提前做成了抽象类,但是是按形状来划分的,而第二次题目是按货物种类划分的,有所区别。
- 第二次作业思维过于活跃(想改变第一次的结构)可能是第一次与第二次题集时间跨度较长,最开始想把抽象的货物类实现费率接口,形成接口-抽象类-类的三重结构,改动太大最后放弃,浪费了时间,最后还是在原来的接口上多实现了两个逻辑,脑子敢想手就刚做,最终力不从心。
- 写题目过程中过于犹豫,总觉得这样不好,有没有更好的,实现了感觉又不好,又换回之前的,浪费太多时间。
改进建议
- 对于类与类之间的关系把握还不到位,要用依赖还是关联,组合还是聚合。
- 对于面向对象六大设计原则运用还不够熟练。
- 代码规范性有待提高,增加更多的注释,便于他人理解,也方便自己以后维护。
- 抽象思维能力不够,什么要做成类,什么不用,是否要合在一起,把握还不到位。
- 与现实结合不足,现实中和做出来的有所差别。
- 不要过于追求完美,适当就行,不然适得其反。
总结
- 老师可以针对每个人的类图进行分析,告诉学生有什么不足,哪里需要改进,可以收获和学到更多。
- 可以设计出更多有意思的题目,锻炼我们的能力。
- 通过第二阶段的学习,对类设计和类与类之间的关系把握更加准确,能够运用六大设计原则处理问题。
- 学会了使用继承与多态,对继承与多态的理解与运用场景更加深刻明确。
- 对于抽象类与抽象方法的使用更加娴熟。