找回密码
 立即注册
首页 业界区 安全 题目集8~9总结性Blog

题目集8~9总结性Blog

孟清妍 2025-5-30 13:33:41
一、前言

对这两次题目集的总结:
这两次题目集相较于上次迭代作业来说,在题目量和难度上都做了下调。但要求我们在理解题目意思、设计好程序结构、掌握并运用知识这三方面有一定的要求。涉及到类的继承与多态,抽象类的设计和抽象方法的灵活运用。以及面向对象的几种程序设计的原则(单一职责原则、里氏代换原则、开闭原则、合成复用原则)。锻炼我们面向接口编程的能力。需要我们不断规范自己的类设计、优化代码结构、降低代码的耦合性,提高程序的可扩展性。

二、设计与分析

因为题目集的前面几题都比较基础,所以该部分重点对航空货物管理系统迭代题做分析。
第一次电梯题目的设计与分析

题目要求:编程实现一个航空货物管理系统,对于订单信息的一些基本数据的输入(客户信息,收件人、发件人、货物信息、航班信息、支付方式等)。还有空运货物的重量计算,以及按照不同的重量区间具有不同的费率。最后一订单表的形式输出。并且本次题目重点考核面向对象设计原则中的单一职责原则、里氏代换原则、开闭原则以及合成复用原则。
类图设计:
1.jpeg

考虑到此次的题目是按照面向对象设计原则来进行打分的,所以类设计的比较多。
类的总体设计



  • Main类: 正确的将数据储存并且由这些数据构建具体实现类,并且能处理货物是否超载的逻辑判断。
  • People类: 作为一个抽象的父类,里面有用户的名字,电话号码,地址的信息,以及Getter、Setter抽象的展示信息方法。
  • Sender类: 该类继承与People类作为一个具体实现类,继承了父类的属性并且实现了父类当中的展示信息方法。
  • Recipient类: 该类继承与People类作为一个具体实现类,继承了父类的属性并且实现了父类当中的展示信息方法。
  • Customer类: 该类继承与People类作为一个具体实现类,继承了父类的属性,同时还有自己的特有的编号属性并且实现了父类当中的展示信息方法。
  • Flight类: 属性有航班的基本信息如始发地、终点和航班的编号。然后有按格式展示航班的基本信息的方法。
  • Freight类: 这个类主要就是用来表示航空货物的一些信息,同时里面还有计算并获取用于计算货物真实重量的方法,并且与下面的货物链表类相关联。
  • FreightList类: 作为货物的容器,主要就是用来计算货物的总重量,以及用于支付类的计算金额。
  • PayMethod接口 主要就是做一个接口来放支付方式的抽象方法,用来展示支付方式。提高代码的可扩展性。
  • RateStrategy接口 接口来放不同费率计算方式的抽象方法,用来确定用哪种费率计算方式。提高代码的可扩展性。
  • PayMent类 组合货物链表和支付方式和费率策略类,用于计算支付订单所需要的总金额,并具有按订单的形式的输出的方法。
  • Order类 具有订单的编号和日期,同样也有按订单信息形式输出的方法。
  • ShowOrder类 组合上面有按订单行动展示自身信息的类,主要控制订单格式的输出的顺序逻辑。

    Source Monitor分析结果:

点此处看方法具体复杂度
3.png

分析与心得

 由上面的Source Monitor分析的结果来看不难发现,这次题目集提交的代码虽然类的设计有很多,但是依旧有不合理的地方,还是有可以改进的地方。


  • 类的职责不够单一 有些具体信息类有展示的方法,并没有完全的做到类的单一职责,应该将这种展示信息的方法分离出来,降低耦合度,提高系统的可扩展性。
  • 代码注释量过少,可读性差:代码的注释量依旧没有达到规范的范围。说明当时在完成这个题目集的时候没有考虑到以后代码还需要不断地改进和维护。
    心得:通过深刻剖析第一次的代码,以及使用特定工具来检查代码不难发现这次的代码在设计合理的类间关系、优化代码结构和增强代码的可读性上面还有很大的改进和提升的空间。

第二次电梯题目的设计与分析

题目要求: 相较于上一次新增了不同的客户类型,不同的货物,不同的支付方式。具体如下折扣率是指不同的用户类型针对每个订单的运费可以享受相应的折扣,在本题中,用户分为个人用户和集团用户,其中个人用户可享受订单运费的 9折优惠,集团用户可享受订单运费的 8折优惠。本次作业费率与货物类型有关,货物类型分为普通货物、危险货物和加急货物三种。支付方式(支付宝支付、微信支付、现金支付)
由于这次有不同的客户类型,不同的货物,不同的支付方式。所以我采用了接口的形式来应对这些不同的情况。
类图:
4.jpeg

设计

将上一次的代码的类设计做出以下的改变,下面是设计的每个类的功能:

  • Main类: 正确的将数据储存并且由这些数据构建具体实现类,并且能处理货物是否超载的逻辑判断。然后新增按照不同的输入类型创建相对应的接口,能够应对此次题目新增的功能。
  • People类: 作为一个抽象的父类,里面有用户的名字,电话号码,地址的信息,以及Getter、Setter。将第一次题目集展示信息的方法剥离出去。
  • Sender类: 该类继承与People类作为一个具体实现类,继承了父类的属性。
  • Recipient类: 该类继承与People类作为一个具体实现类,继承了父类的属性。
  • Customer类: 该类继承与People类作为一个具体实现类,继承了父类的属性,同时还有自己的特有的编号属性。
  • Flight类: 属性有航班的基本信息如始发地、终点和航班的编号。
  • Freight类: 这个类主要就是用来表示航空货物的一些信息,同时里面还有计算并获取用于计算货物真实重量的方法,并且与下面的货物链表类相关联。
  • FreightList类: 作为货物的容器,主要就是用来计算货物的总重量,以及用于支付类的计算金额。
  • PayMethod接口 主要就是做一个接口来放支付方式的抽象方法,用来展示支付方式。提高代码的可扩展性。
  • RateStrategy接口 该接口来放不同费率计算方式的抽象方法,用来确定用哪种费率计算方式。提高代码的可扩展性。
  • DiscountStrategy接口 该接口来放不同客户类型的折扣计算方式的抽象方法,用来确定用哪种折扣计算方式。提高代码的可扩展性。
  • PayMent类 组合货物链表和支付方式和费率策略类,用于计算支付订单所需要的总金额。
  • Order类 对比上次题目的类该类具有订单的编号和日期,还组合了客户,收件人,发件人,航班信息。将这些信息的展示方式放在这个类当中来展示。做好类的单一职责(SPR)。
  • OrderDetais类 新增订单明细类,组合支付类,和货物链表类。主要就是用来展示一些有关于订单金额信息的类。进一步解耦,提高扩展性。
  • ShowOrder类 组合上面订单类和订单明细类,展示订单信息的类,主要控制订单格式的输出的顺序逻辑。
Source Monitor分析结果:
5.png

点此处看方法具体复杂度
6.png

分析与心得

由上面的Source Monitor分析的结果来看,第二次提交的通过代码在新增了不同类型的处理情况后,代码行数从 ​​510 增至 ​​670​​,设计多个接口和做到展示信息的和订单信息职责拆分后新增OrderDetails类,符合接口编程的设计预期。质量明显要比第一次的好的多,但是还是存在一些问题的:


  • 代码的注释还是太少:注释量站的百分比下降,可能是因为在重新设计类后,代码行数的增多,导致第二次的逻辑部分即使增加了代码注释,注释的量依旧没有达到Java规范的量。
  • 代码的最大复杂度增加: 代码的最大复杂度比上次提高了,说明在某个方法的调用或者计算的方式依旧有可以提升的空间。
    心得:虽然这次的代码仍有两个方面没有达到要求的范围,但相比上次题目集已经有了很大的改进了,不过还是要养写代码注释的习惯,尤其是逻辑部分和调用方法部分。使代码逻辑容易理解和调试,符合Java编程原则规范了。

三、踩坑心得

本部分对每次题目集提交代码出现的问题和心得进行总结



  • 1.不能正确的构建具体类:在主方法里使用nextLine来解析输入的数据时,总是忘记把String类型的数据转换为对应的数据类型。还有就是传入的构造数据的顺序老是弄错。导致了不能正确的构建具体实现类,进而浪费了一些时间。
  • 2.无法获取父类的属性 在编写代码的时候,把父类的属性设置为了private的,然后又没设计get方法导致无法获取属性。
  • 3.超载信息提示的格式错误 第一次提交的时候回答详情里面超载信息的那部分显示格式错误,一开始我以为是航班号的信息有问题,浪费了一些时间在检查航班类的构建和信息输出上面。后面才发现,我是在main方法里面运用println输出超载信息的时候“”里面忘记加一个空格导致的格式错误。
四、改进建议

点击查看可改进的代码
  1.     static public void main(String[]args){
  2.         Scanner sc = new Scanner(System.in);
  3.         // 读取客户信息
  4.         String customerNumber = sc.nextLine();
  5.         String customerName = sc.nextLine();
  6.         String customerTel = sc.nextLine();
  7.         String customerAddress = sc.nextLine();
  8.         //创建客户
  9.         Customer customer = new Customer(customerNumber, customerName, customerAddress, customerTel);
  10.         // 读取货物数量
  11.         int freightCount = Integer.parseInt(sc.nextLine());
  12.         FreightList freightList = new FreightList();
  13.         // 读取每个货物信息
  14.         for (int i = 0; i < freightCount; i++) {
  15.             Freight freight = new Freight(
  16.                     sc.nextLine(),//number
  17.                     sc.nextLine(), // name
  18.                     Double.parseDouble( sc.nextLine()), // width
  19.                     Double.parseDouble( sc.nextLine()), // length
  20.                     Double.parseDouble( sc.nextLine()), // height
  21.                     Double.parseDouble( sc.nextLine())//weight
  22.             );
  23.             freightList.addFreight(freight);
  24.         }
  25.         // 读取航班信息
  26.         Flight flight = new Flight(
  27.                 sc.nextLine(), // flightNumber
  28.                 sc.nextLine(), // departure
  29.                 sc.nextLine(), // arrival
  30.                 sc.nextLine(), // date
  31.                 Double.parseDouble(sc.nextLine()) // maxcapacity
  32.         );
  33.         //判断重量是否满足该航班的最大容量
  34.         if(freightList.calculateTotalWeight()>flight.getMaxcapacity()){
  35.             System.out.println("The flight with flight number:"+flight.getFlightNumber()+" has exceeded its load capacity and cannot carry the order.");
  36.             return;
  37.         }
  38.         // 读取订单信息
  39.         Order order = new Order(
  40.                 sc.nextLine(), // number
  41.                 sc.nextLine()  // date
  42.         );
  43.         // 读取发件人信息
  44.         String senderAddress = sc.nextLine();
  45.         String senderName = sc.nextLine();
  46.         String senderTel = sc.nextLine();
  47.         Sender sender = new Sender(senderName, senderAddress, senderTel);
  48.         // 读取收件人信息
  49.         String recipientAddress = sc.nextLine();
  50.         String recipientName = sc.nextLine();
  51.         String recipientTel = sc.nextLine();
  52.         Recipient recipient = new Recipient(recipientName, recipientAddress, recipientTel);
  53.         //创建费率
  54.         Rate rate=new Rate();
  55.         // 创建支付类
  56.         Payment payment = new Payment(new WeChatPay(),freightList,rate);
  57.         // 创建Show实例并显示
  58.         ShowOrder show = new ShowOrder(customer, freightList, flight, payment, sender, recipient, order);
  59.         show.showOrderInformation();
  60.         sc.close();
复制代码
做好类的单一职责,降低耦合度

 在这段Main类的的main方法里面有超载的逻辑判断和输出没有很好的做到类的职责单一原则,可以将这个逻辑判断单拎出来。
添加合适的注释,增强代码可读性

 一些复杂的构造和调用方法并没有注释。这就会导致,当自己再次阅读代码或者别人查看代码时,会变得很吃力,所以需要给出合适的代码注释,增强代码的可读性。
五、总结

收获和建议:

收获

  在完成航空货物管理系统的过程中,最大的收获在于对面向对象设计原则的具象化理解与应用。通过两次迭代题目,我逐步体会到单一职责原则(SRP)如何通过拆分 “展示逻辑” 与 “业务逻辑”(如将订单信息输出从Order类剥离至ShowOrder类)降低类的复杂度;里氏代换原则(LSP)要求子类完全替代父类的场景(如Sender/Recipient继承People并实现统一接口),避免因子类行为差异导致的程序崩溃;开闭原则(OCP)则通过引入RateStrategy/DiscountStrategy接口,在新增货物类型或客户折扣时仅需扩展实现类而非修改原有代码,显著提升系统可维护性。
  此外,这次的航空货物管理系统也让我对 “接口编程” 思维有了一个具体化的了解。例如,将支付方式抽象为PayMethod接口,使支付宝、微信支付等具体实现可动态替换,这种 “面向抽象而非实现” 的设计极大减少了模块间的耦合。同时,通过FreightList类封装货物集合的操作,实现了数据存储与业务逻辑的分离,符合合成复用原则(CRP),避免了继承带来的紧耦合问题。
  最后虽然这次的题目让我收获颇丰,但还是有一些方面需要进一步的学习和研究的。比如:深入去了解,什么时候将方法抽象出来好,什么时候不要把方法抽象出来。跟深入的去了解这些不同设计所带来的优势和不同。在今后的编程当中更加主动去重视面向对象程序设计原则,规范自己的代码结构!
建议

最后根据这次迭代作业,给面向对象程序设计课题组的一些建议:
可以在迭代的题目集完全结束后给出规范合理的类设计结构给同学们学习、改进最终提升自己的编程能力
你在完成航空货物系统时遇到了哪些挑战?欢迎在评论区分享你的解决方案!感谢您的阅读!

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册