Blog 2:题目集08-09分析

Blog 2:题目集08-09分析

前言

题目集8-9与前几次的题目集相比,算法层面的挑战有所降低,但对类设计的考察要求显著提升,更注重检验对类体系构建、结构设计的深层理解。这两次的题目集题量不大,但题目阅读量较高,大幅增加了信息提取和题意理解的难度,需要应试者具备较强的文本解读能力、逻辑梳理能力以及将自然语言转化为程序设计语言的抽象思维。题目聚焦于面向对象编程的核心知识点,尤其是继承与多态机制的灵活运用,以及接口类设计的规范性和扩展性。这两次题目集里的题目要求我们理解如何通过类设计优化程序结构、提升代码可维护性,体现了从 “实现功能” 到 “设计架构” 的能力进阶。

设计与分析

航空货运管理系统(类设计)

该航空货运管理系统源码设计了8个类。Main是程序入口,协调其他类工作。customerInformation存储客户信息,Delivery和Reception分别管理发货和收货方信息,flightInformation负责航班信息,freightInformation处理货物信息及计费重量计算,order管理订单,fee用于计算费用,但职责混乱,应优化整合。总体来说类设计基本覆盖核心业务,但存在部分结构与逻辑问题。类间关系上,Delivery和Reception对customerInformation的继承不合理,应改为组合关系;fee类依赖freightInformation计算费用,导致职责不清。在代码质量上存在命名不规范(类名未遵循大驼峰命名法)、计算冗余等问题。代码复杂度较高。较高的复杂度意味着代码逻辑可能较复杂,维护难度较大。最大深度 4 和平均深度 2.14、平均复杂度 1.85,反映了代码结构的嵌套层次和整体复杂程度。整体而言,该项目代码在可读性、可维护性上有提升空间。可以通过重构继承体系、统一命名规范来优化代码,提升代码的可维护性与健壮性。

aviationFreightClassDiagram

航空货运管理系统(继承与多态)

该题源码是在上次源码的基础之上的迭代,相较于之前,在类的细化与继承上做了文章。整体来看,项目有 18 个类,代码行数共 559 行,语句 349 条,分支占比 9.5% ,调用 105 次。新增了Individual和Corporate类继承customerInformation,用于区分个人客户和企业客户;Normal、Expedite、Dangerous类继承freightInformation,细分货物类型。这种继承关系使代码结构更清晰,增强了扩展性。新增功能类以实现支付功能,引入Discount类处理不同客户类型的折扣计算,Payment及其子类(Alipay、Cash、Wechat)实现多种支付方式选择,丰富了业务逻辑。类的划分结构相对完整与清晰,设置了客户类customerInformation存储客户通用信息,并划分子类Individual和Corporate在此基础上区分客户性质。Delivery和Reception分别负责发件人和收件人信息管理。与运输相关类flightInformation管理航班信息,order处理订单信息。设计了货物与费用类,freightInformation及其子类dangerous,expedite,normal类管理三种不同货物属性,fee类依据货物类型计算费用,但是在费用计算上逻辑较复杂,代码行数与方法数较多,可考虑拆分以降低复杂度。以及设计了Discount根据客户类型计算折扣,Payment及其子类alipay,wechat,cash实现三种不同支付方式选择,但行数和语句数少,逻辑简单。总体而言,项目代码需对复杂类进行重构优化,提升可维护性与可读性。与迭代之前的代码相比,代码结构更合理,类的职责划分更明确,可维护性和扩展性提升,能较好应对业务变化。当前代码通过类继承实现了基本的多态性,但仍存在较多缺点与问题,如Delivery和Reception仍继承customerInformation存在设计缺陷,发货方和收货方本质是订单关联角色,而非客户类型,应改为组合关系。以及fee代码冗余,算法重复,职责不清晰问题依然存在。建议重构fee类,将不同货物的计费逻辑封装到独立策略类中,消除条件判断。优化方向可以聚焦于设计模式应用、职责分离和数据结构升级,以此来优化代码,提升代码的可扩展性和可维护性。

魔方问题

该题源码几何实体与魔法方块的类体系。抽象类Geometry定义边长属性及面积、体积计算接口,具体子类Cube(立方体)和TriangularPyramid(三角锥)实现基础计算逻辑,其中立方体面积计算单面面积,三角锥体积公式适用于正四面体场景。抽象类MagicCube则扩展颜色、层数属性,通过组合Geometry子类实例,实现多层结构的面积与体积计算,其子类CubicCube和TriangularPyramidCube分别针对立方体和三角锥,通过层数的平方和立方放大基础值。主类Main通过多态接收用户输入,统一调用子类方法输出结果。总体类结构层次分明,抽象与继承关系清晰,多态机制实现代码复用,参数化层数设计符合开闭原则,便于扩展新几何类型。但仍存在不足,首先健壮性不足,未校验输入参数合法性(如边长、层数为负数);其次测试缺失,分支与语句覆盖率均为 0,难以保障逻辑正确性。

屏幕截图 2025-05-22 101217

屏幕截图 2025-05-22 101753

踩坑心得

这两次题目集的题目的题目虽在算法难度上未设置过高门槛,看似易于实现,但程序编写的实操环节却也不是那么简单容易的,仍然出现了许多问题,踩了许多坑。这些问题不仅暴露了编码习惯的不严谨,更让人深刻意识到编程绝非单纯的算法堆砌,而是对细节把控、逻辑严密性与问题排查能力的综合考验。以下是我编写过程中遇见的问题,希望能吃一堑长一智,以后尽量不要再出现类似的问题。

对象初始化不完整

在航空货运系统(继承与多态)的源码中,子类调用父类构造函数时没有传递类型参数,导致 freightType 字段未被初始化。程序在运行时抛出了 NullPointerException,具体原因是 freightInformation.getFreightType() 返回了 null,导致在 fee.feeType() 方法中调用 equals 方法时出现异常。freightInformation 类有一个 freightType 字段用于存储货物类型。当通过子类(如 Normal、Expedite、Dangerous)创建对象时,子类的构造函数调用了父类的构造函数,但没有正确设置 freightType 字段。因此,freightType 字段的值为 null,当调用 getFreightType() 方法时返回 null,进而在调用 equals() 方法时引发 NullPointerException。

解决办法也很简单,即确保父类构造函数初始化所有关键字段以及子类构造函数必须传递类型参数。我在修改时选择使用freightType的setter方法正确初始化type,即在main方法里添加freight.setFreightType(fType)语句。修改之后freightType成功被初始化,程序可以正常输出不报错。

花括号缺省问题

在多次作业题目里出现了该问题,写着写着到方法或类结束时忘记添上闭合花括号,或是调整代码行,以及对代码进行复制粘贴拖到等编辑操作时忽略了代码结构的对称性,遗忘了花括号,操作之后也未检查,导致该问题时常发生。一个很愚蠢的问题,但也很能反映问题,暴露出编码习惯的疏漏即细节把控力不足与收尾检查意识薄弱。

输入类型错误问题

在航空货运系统(类设计)里出现该问题次数较多。从编译器给出的错误信息 java.util.InputMismatchException 可知,Scanner 在尝试读取输入时,碰到了与预期类型不相符的数据。具体而言,scanner.nextInt() 方法期望读取一个整数。要是输入并非有效的整数,就会抛出 InputMismatchException 异常。这由于输入包含非数字字符,或者输入格式非法。该题的输入内容较多,所以在输入时未校对号输入数据的类型,导致该行我输入的是一个字符型的字符串,从而报错。

类型声明问题

在航空货运系统(类设计)的源码里,在创建ArrayList时,没有指定泛型类型,这可能会导致类型安全问题。

正确的声明方法应该是这样的:

代码冗余问题

在航空货运系统(类设计)的源码里,计算总费用时,你使用了 for (int i = 0; i < amount; i++) 循环,而在输出货物明细时使用了 for (int i = 0; i < freightList.size(); i++)循环。由于 amount 和 freightList.size() 是等价的,所以可以统一使用 freightList.size() 来避免混淆。

数据输出失败问题

在航空货运系统的源码里,当计算并输出费率和应交运费时,程序输出的结果均为0.0,不符合我的预期结果。查找原因如下:在 fee 类的构造函数中,没有对 freight 成员变量进行合理赋值。当前构造函数 public fee(double rate,double fee,freightInformation freight) 中,虽然有 freight 参数,但并没有将其赋值给类的成员变量 freight ,导致后续在计算和获取相关费率、运费时,freight 为 null ,引发错误。以及计算逻辑与输出时机存在问题,在计算总费用的循环中,虽然计算了每个货物的费用,但没有正确获取费率和费用进行输出。在输出货物明细时,获取费率和费用的代码存在问题。

IMG_256

对代码作出相应的修改之后可以成功输出预期结果。

改进建议

对于航空货运系统的源码来说,可以优化、可以改进的地方还是比较多的。首先,可以提升代码复用与模块化,可以提取公共逻辑以解决fee 类和 freightInformation 中的重量计算逻辑重复。建议将重量计算逻辑(如 getActualWeight())封装到 freightInformation 中,并确保计算逻辑一致。在 fee 类中直接调用 freight.getActualWeight(),避免逻辑重复。其次,可以类的设计方面进行优化,如修改customerInformation与delivery和reception的类间关系可以修改,应改为组合关系。再者,还可完善访问修饰符问题,部分属性和方法的访问修饰符不够严格(如 order 类的 order 字段为默认访问)。应该明确设置属性为 private,并通过 getter、setter 访问,对不需要外部调用的方法使用 private 修饰。然后,还可以添加对输入的处理与对异常情况的处理,添加输入验证进行有效性检查(如负数重量、无效日期格式),确保数据合法性。

对于迭代后的航空货运系统源码来说,也有许多可完善的空间。首先继承结构可以改进,目前Individual和Corporate直接继承customerInformation,但没有充分利用多态特性。可以在父类中定义抽象方法,如getDiscountRate(),让子类根据客户类型返回不同的折扣率。类似地,Normal、Expedite和Dangerous作为freightInformation的子类,应重写计费相关方法,而不是依赖外部的fee类。其次,可以移除冗余类,fee类的设计略显不合理,它与freightInformation耦合度高,可以将计费逻辑直接移到freightInformation子类中。再者,可以优化main方法的代码结构,对其进行拆分以减少代码赘余,降低复杂度,将输入处理、业务逻辑和输出分离,提高代码可读性。

总结

这两次题目集的作业不难,但仍有许多暗藏的坑,有些坑被我蠢蠢地踩了,但有些坑我幸运地避开了。总的来说,通过这两次的题目集作业,我深入理解了面向对象编程的核心思想:将客户类型、支付方式、货物类型等抽象为独立子类,通过继承父类并在构造函数中显式传递类型参数,确保对象状态完整,避免硬编码和空指针异常。过程中学会分析继承链中字段初始化的逻辑,例如freightInformation子类需在构造时为freightType赋值,防止null值引发运行时错误。同时,掌握了继承与多态的应用,学会了通过继承避免代码冗余(如 Delivery 和 Reception 继承 customerInformation),通过父类引用子类对象实现多态(如 customer.showInformation() 自动调用子类方法)。理解子类如何重写(@Override)父类方法(如 Alipay 重写 Payment 的支付方式)。还培养了调试思维,通过对比输入样例与输出结果,学会逐步排查逻辑错误(如费用计算错误、输出格式错位)。掌握通过打印中间变量(如 totalWeight、rate)定位问题的方法。并深刻体会到遵循单一职责原则对代码可维护性的提升:各类型子类独立封装逻辑,后续扩展新类型时只需新增子类,无需修改原有代码,真正实现“对扩展开放,对修改关闭”。但我在作业中中同时深刻意识到自身存在诸多亟待提升的短板。当用户输入非预期数据时,程序常因缺乏健壮的异常处理机制而崩溃 —— 比如用字符串响应数值输入需求时,Scanner会抛出InputMismatchException却未被捕获,导致程序终止。在面对复杂业务规则时,会导致代码膨胀且维护成本激增,时间复杂度也无法满足大规模数据处理需求。这些不足既是挑战也是成长契机,我将继续奋斗,深入研究算法复杂度分析与数据结构优化,结合具体场景实践设计模式,逐步提升代码的健壮性、效率与可维护性。

意见

希望老师能够多给点提示,例如题目测试点未过,能给出具体原因,或是该测试点的具体情况是哪种情形,以便我们对代码进行检查和修改。还有就是,对于扣分的题目,也希望老师能够给出具体原因。

24201637-张睿

posted @ 2025-05-22 19:27  Rayyy_yyy  阅读(33)  评论(0)    收藏  举报