题目集8,9Blog
-
前言:
在第8、9次作业中,我通过航空货运管理系统的开发,进一步巩固了Java语法知识,特别是在集合框架、多线程和异常处理方面的应用,能够更加灵活地运用这些语法特性解决实际问题。同时,我对类的设计有了更深入的理解,明确了单一职责原则的重要性,通过合理划分类的职责,使代码更加清晰可维护。在类的继承和多态应用中,我学会了如何通过抽象类和接口实现代码复用和灵活扩展,遵循里氏代换原则和开闭原则,提升了系统的可扩展性和可维护性。此外,我还体会到了合成复用原则在构建复杂系统时的作用,通过组合多个对象来实现功能,避免了过度继承带来的问题。 -
Complexity Metrics(复杂度分析)
因为下面要用到复杂度分析,所以先在此给出一些相关概念。
我们需要使用的主要是方法和类的复杂度分析。
方法的复杂度分析主要基于循环复杂度的计算。循环复杂度是一种表示程序复杂度的软件度量,由程序流程图中的“基础路径”数量得来。
ev(G):即Essentail Complexity,用来表示一个方法的结构化程度,范围在[1,v(G)]之间,值越大则程序的结构越“病态”,其计算过程和图的“缩点”有关。
iv(G):即Design Complexity,用来表示一个方法和他所调用的其他方法的紧密程度,范围也在[1,v(G)]之间,值越大联系越紧密。
v(G):即循环复杂度,可以理解为穷尽程序流程每一条路径所需要的试验次数。
对于类,有OCavg和WMC两个项目,分别代表类的方法的平均循环复杂度和总循环复杂度。 -
设计分析:
题目8:
- 题目需求:
本次题目模拟某客户到该航空公司办理一次货运业务的过程,程序需要从键盘依次输入填写订单需要提供的信息,然后分别生成订单信息报表及货物明细报表。
2.类图设计:

3.使用SourceMonitor对代码进行复杂度分析:

- 代码分析:
(1)功能概述:
①.Flight 类(航班类)
属性
number:航班号
startAirport:出发机场
endAirport:到达机场
date:航班日期
maxWeight:航班最大载重
构造方法
默认构造方法和带参数的构造方法,用于初始化航班信息。
方法
提供了 getNumber、getStartAirport、getEndAirport、getDate、getMaxWeight 等 getter 方法,用于获取航班的属性值。
③.OrderForm 类(订单表单类)
属性
number:订单号
date:订单日期
构造方法
默认构造方法和带参数的构造方法。
方法
提供了 getNumber 和 getDate 等 getter 方法。
④.Person 类(人员类)
属性
name:姓名
callNumber:联系电话
address:地址
构造方法
默认构造方法和带参数的构造方法。
方法
提供了 getName、getCallNumber、getAddress 等 getter 方法。
⑤.Customer 类(客户类,继承自 Person)
属性
number:客户编号
cargos:货物信息列表(ArrayList)
orderForm:订单表单
构造方法
默认构造方法和带参数的构造方法。
方法
提供了 getNumber、getCargo、addCargo、setOrderForm 等方法。
allWeight:计算所有货物的总重量。
allPrice:计算所有货物的总价格。
⑥.Sender 类(发件人类,继承自 Person)
属性
无额外属性。
构造方法
带参数的构造方法。
⑦.Receiver 类(收件人类,继承自 Person)
属性
无额外属性。
构造方法
带参数的构造方法。
⑧.Main 类(主类)
方法
main:程序入口,负责接收用户输入,创建对象,并输出订单信息。
(3)主流程
用户输入客户信息(编号、姓名、电话、地址)。
用户输入货物信息(编号、名称、长、宽、高、毛重),可以输入多条货物信息。
用户输入航班信息(航班号、出发机场、到达机场、日期、最大载重)。
用户输入订单信息(订单号、日期)。
用户输入发件人和收件人的信息(姓名、电话、地址)。
系统检查货物总重量是否超过航班的最大载重。
如果不超过载重,输出订单的详细信息,包括航班号、订单号、发件人和收件人信息、货物明细、总重量和总金额。
如果超过载重,输出提示信息,说明航班无法承载该订单。
(4)代码优点
该代码的优点在于其清晰的模块化设计和面向对象的实现方式。通过将航班、货物、订单、客户等信息分别封装为独立的类,代码结构层次分明,逻辑清晰,便于开发者理解和维护。这种模块化的设计方式不仅提高了代码的可读性,还使得各个功能模块之间的耦合度较低,便于后续的扩展和修改。例如,如果需要增加新的货物类型或调整订单处理逻辑,只需修改相关类即可,而不会对其他模块产生过多影响。
代码还充分利用了继承机制,Customer、Sender 和 Receiver 类继承自 Person 类,复用了 Person 类的属性和方法,减少了代码冗余,提高了代码的可复用性。同时,每个类都提供了完整的 getter 和 setter 方法,严格遵循了封装原则,确保了数据的安全性和完整性,使得类的属性不会被外部直接访问和修改,只能通过方法进行操作,进一步增强了代码的健壮性。
此外,代码的主流程逻辑清晰,从用户输入到订单生成和验证的过程一目了然,便于调试和测试。整体而言,代码的设计思路合理,能够较好地满足航空货运管理系统的基本需求,为后续的功能扩展和优化提供了一个良好的基础。
(5)代码不足
该代码在功能实现上虽然具备一定的模块化和面向对象的设计思想,但仍存在一些明显的不足之处。首先,代码缺乏对用户输入的有效验证机制,无法确保输入数据的合法性和合理性,例如货物的尺寸、重量是否符合实际运输要求,或者航班号、订单号是否符合特定格式等。这种缺失可能导致程序在运行过程中因非法输入而出现错误或异常行为。其次,代码中未对可能出现的异常情况进行妥善处理,例如货物总重量超过航班载重时,仅简单输出提示信息,而未提供进一步的解决方案或替代选项。此外,代码的扩展性有限,若需支持更多功能(如多种计费方式或运输方式),需进行较大改动。同时,Sender 和 Receiver 类仅简单继承 Person 类,未添加额外功能,显得冗余且降低了代码复用性。最后,程序的用户交互体验较差,输入方式单一且缺乏友好提示,不利于实际应用中的用户体验。
题目9:
- 题目需求:
本次题目模拟某客户到该航空公司办理一次货运业务的过程,程序需要从键盘依次输入填写订单需要提供的信息,然后分别生成订单信息报表及货物明细报表。
2.类图设计:

3.使用SourceMonitor对代码进行复杂度分析:

- 代码分析:
(1)功能概述
该代码实现了一个航空货运管理系统,支持用户输入客户信息、货物信息、航班信息、订单信息以及发件人和收件人的详细信息。系统会根据货物的毛重和体积重量计算计费重量,并根据货物类型(普通、危险品、加急)和客户类型(个人、企业)计算运费。最后,系统会检查货物总重量是否超过航班的最大载重能力,并输出订单的详细信息,包括航班号、订单号、发件人和收件人信息、货物明细、总重量和总金额。
(2)类的结构和功能
①.Flight 类(航班类)
属性
number:航班号
startAirport:出发机场
endAirport:到达机场
date:航班日期
maxWeight:航班最大载重
构造方法
带参数的构造方法,用于初始化航班信息。
方法
提供了 getNumber 和 getMaxWeight 等 getter 方法,用于获取航班的属性值。
②.CargoInformation 类(货物信息类)
属性
number:货物编号
name:货物名称
length、width、height:货物的长、宽、高
grossWeight:货物毛重
volumeWeight:体积重量(根据长宽高计算)
weight:计费重量(取毛重和体积重量的最大值)
price:货物价格
rate:计费费率
type:货物类型(普通、危险品、加急)
构造方法
初始化货物信息,并计算体积重量、计费重量和价格。
方法
提供了 getWeight、getGrossWeight、getVolumeWeight、getLength、getWidth、getHeight、getNumber、getName、getPrice 等 getter 方法。
calculateVolumeWeight:计算体积重量。
chooseWeight:选择毛重和体积重量的最大值作为计费重量。
setPrice:根据货物类型和计费重量设置价格。
③.OrderForm 类(订单表单类)
属性
number:订单号
date:订单日期
构造方法
带参数的构造方法。
方法
提供了 getNumber 和 getDate 等 getter 方法。
④.Person 类(人员类)
属性
name:姓名
callNumber:联系电话
address:地址
构造方法
带参数的构造方法。
方法
提供了 getName、getCallNumber、getAddress 等 getter 方法。
⑤.Customer 类(客户类,继承自 Person)
属性
number:客户编号
cargos:货物信息列表(ArrayList)
orderForm:订单表单
type:客户类型(个人、企业)
构造方法
带参数的构造方法。
方法
提供了 getNumber、getCargos、getOrderForm、addCargo、setOrderForm 等方法。
allWeight:计算所有货物的总重量。
allPrice:计算所有货物的总价格,并根据客户类型(个人、企业)提供折扣。
⑥.Sender 类(发件人类,继承自 Person)
属性
无额外属性。
构造方法
带参数的构造方法。
⑦.Receiver 类(收件人类,继承自 Person)
属性
无额外属性。
构造方法
带参数的构造方法。
⑧.Main 类(主类)
方法
main:程序入口,负责接收用户输入,创建对象,并输出订单信息。
(3)主流程
用户输入客户信息(编号、姓名、电话、地址、客户类型)。
用户输入货物信息(编号、名称、长、宽、高、毛重、货物类型),可以输入多条货物信息。
用户输入航班信息(航班号、出发机场、到达机场、日期、最大载重)。
用户输入订单信息(订单号、日期)。
用户输入发件人和收件人的信息(姓名、电话、地址)。
用户输入支付方式(支付宝、微信、现金)。
系统检查货物总重量是否超过航班的最大载重。
如果不超过载重,输出订单的详细信息,包括航班号、订单号、发件人和收件人信息、货物明细、总重量和总金额。
如果超过载重,输出提示信息,说明航班无法承载该订单。
(4)代码的优点
该代码采用了面向对象的设计思想,通过合理的类封装和模块化设计,将航班、货物、订单、客户等信息分别抽象为独立的类,使得代码结构清晰、层次分明,便于理解和维护。同时,代码利用继承机制实现了客户、发件人和收件人的复用,减少了代码冗余,提高了代码的可扩展性和可重用性。每个类都提供了完整的 getter 和 setter 方法,严格遵循了封装原则,确保了数据的安全性和完整性。此外,代码还支持多种货物类型和客户类型的定价策略,增强了系统的灵活性和实用性。
(5)代码的不足之处
该代码虽然实现了航空货运管理系统的基本功能,但仍存在一些明显的不足。首先,代码缺乏对用户输入的有效验证,无法确保输入数据的合法性,例如货物的尺寸、重量是否合理,航班号、订单号是否符合格式等,这可能导致程序在运行过程中因非法输入而出现错误或异常行为。其次,代码中未对可能出现的异常情况进行妥善处理,例如货物总重量超过航班载重时,仅简单输出提示信息,而未提供进一步的解决方案。此外,代码的扩展性有限,若需支持更多货物类型或客户类型,需进行较大改动。同时,Sender 和 Receiver 类只是简单继承了 Person 类,未添加额外功能,显得冗余且降低了代码复用性。最后,程序的用户交互体验较差,输入方式单一且缺乏友好提示,不利于实际应用中的用户体验。这些不足之处限制了代码的健壮性、灵活性和实用性,需要进一步优化以提升系统的整体质量。
-
踩坑心得:
输入验证不足
两段代码都没有对用户输入进行严格的验证。例如,货物的尺寸、重量是否在合理范围内,航班号、订单号是否符合特定格式等。如果用户输入非法数据(如负数、空字符串或不符合格式的日期),程序可能会抛出异常或产生错误的计算结果。输入验证是程序稳定性的第一道防线。在实际开发中,必须确保用户输入的数据符合业务逻辑和数据类型的要求。可以通过正则表达式、范围检查等方式对输入进行验证,并在发现非法输入时及时提示用户重新输入。
异常处理缺失
两段代码都没有对可能出现的异常情况进行处理。例如,如果用户输入的货物总重量超过航班的最大载重,程序只是简单地输出提示信息,而没有进一步的处理逻辑。此外,代码中也没有处理其他可能的异常,如输入格式错误、数组越界等。异常处理是程序健壮性的关键。在实际开发中,应该使用 try-catch 块捕获可能的异常,并提供合理的错误处理逻辑。例如,可以记录错误日志、提示用户重新输入或提供默认值等。同时,应该尽量避免程序因未捕获的异常而崩溃。
扩展性有限
两段代码虽然模块化程度较高,但在某些方面扩展性仍有不足。例如,如果需要支持更多货物类型或客户类型,需要对代码进行较大的修改。此外,Sender 和 Receiver 类只是简单继承了 Person 类,没有添加任何额外的功能,显得冗余且降低了代码复用性。在设计系统时,应该尽量考虑未来可能的扩展需求。可以使用设计模式(如工厂模式、策略模式)来提高代码的灵活性和可扩展性。同时,应该避免过度设计,确保代码的简洁性和可维护性。对于冗余的类,可以考虑直接使用父类的实例来代替,减少代码的复杂性。
用户交互体验差
两段代码的输入方式较为简单,用户需要按照固定的格式输入数据,且没有提示信息。在实际应用中,这种交互方式可能会给用户带来不便,尤其是在输入大量数据时容易出错。用户交互体验是系统成功的关键之一。在实际开发中,可以考虑使用图形用户界面(GUI)或更友好的交互方式来提升用户体验。例如,可以使用表单输入、下拉菜单、自动提示等功能,帮助用户更方便地输入数据。同时,应该在用户输入错误时提供清晰的错误提示,帮助用户快速纠正错误。
代码复用性低
Sender 和 Receiver 类只是简单继承了 Person 类,没有添加任何额外的功能。这种设计显得冗余,降低了代码的复用性。在设计类时,应该尽量避免冗余的继承。如果子类没有添加任何新的功能或属性,可以直接使用父类的实例来代替。这样可以减少代码的复杂性,提高代码的可维护性。同时,应该合理使用继承和组合,确保代码的结构清晰、层次分明。
硬编码问题
在两段代码中,支付方式的处理是硬编码的(如将字符串 "ALiPay" 转换为 "支付宝")。这种硬编码的方式使得代码的可维护性较差,如果需要添加新的支付方式,需要修改代码逻辑。在实际开发中,应该尽量避免硬编码。可以使用配置文件或数据库来管理这些常量,使得系统更加灵活和易于维护。例如,可以将支付方式存储在配置文件中,并在程序启动时加载这些配置。这样,当需要添加新的支付方式时,只需修改配置文件,而无需修改代码。
性能问题
在 Customer 类中,allWeight 和 allPrice 方法每次调用时都会重新计算总重量和总价格。如果货物列表较大,这可能会导致性能问题。在实际开发中,应该尽量减少重复计算。可以通过缓存计算结果来提高性能。例如,可以在 Customer 类中添加两个字段来存储总重量和总价格,并在添加或删除货物时更新这些字段的值。这样,每次调用 allWeight 和 allPrice 方法时,可以直接返回缓存的结果,而无需重新计算。 -
总结:
通过对两段航空货运管理系统代码的分析,我们发现了一些常见的问题,如输入验证不足、异常处理缺失、扩展性有限、用户交互体验差、代码复用性低、硬编码问题和性能问题。这些问题在实际开发中可能会导致程序的健壮性、灵活性和用户体验下降。因此,在开发过程中,我们应该注重代码的质量,遵循良好的编程实践,确保系统的稳定性和可维护性。具体来说,应该加强输入验证、完善异常处理、提高代码的扩展性和复用性、优化用户交互体验、避免硬编码,并通过缓存等方式提高性能。只有这样,我们才能开发出高质量、高可用性的软件系统。
浙公网安备 33010602011771号