Blog2-类的设计

                                                                                                                        BLOG 2

编程学习的旅程,恰似一场不断雕琢的工艺之旅。从初窥面向对象的门径,到深入复杂系统的架构设计,每一次键盘的敲击都是对逻辑的淬炼,每一次代码的重构都是对思维的重塑。在这段旅程中,我们以 “点线面” 为笔,勾勒几何世界的抽象轮廓;以 “雨刷系统” 为轴,转动状态管理的精密齿轮;以 “航空货运” 为镜,映照业务逻辑的复杂万象;更以 “魔方问题” 为尺,丈量立体几何的计算精度。
题目量与难度都算适中,较好的给到了我们对类以及多态继承的锻炼。
这些项目如同拼图的碎片,看似独立却共同拼绘出面向对象编程的完整图景:从抽象类与接口的顶层设计,到继承体系的层次搭建;从多态特性的灵活运用,到容器类对对象的动态管理;从单一职责原则的恪守,到状态模式、中介模式的巧妙实践。每一个项目都是一次 “从无到有,从有到优” 的蜕变 —— 我们曾为类职责的混杂而反复调试,为多态调用的逻辑而彻夜思索,为业务规则的复杂度而重构架构,却也在最终代码运行通过的那一刻,深刻体会到 “清晰的类结构、优雅的设计模式、健壮的业务逻辑” 带来的成就感。接下来,我将详细分享在这些项目中的实践过程、遇到的挑战以及收获的宝贵经验,希望能与大家一同探讨面向对象编程的魅力与精髓,为编程学习之路提供更多的思考与启发(每个题目集都是自己实打实敲出来的都是经历过熬夜的更改最终不负众望取得高分)。
第八次作业
第一道是点线面问题重构(继承与多态):
这道题目是对前几次的点线面的迭代,这次主要以继承与多态为主:对题目中的点Point类和线Line类进行进一步抽象,定义一个两个类的共同父类Element(抽象类),将display()方法在该方法中进行声明(抽象方法),将Point类和Line类作为该类的子类。再定义一个Element类的子类面Plane,该类只有一个私有属性颜色color,除了构造方法和属性的getter、setter方法外,display()方法用于输出面的颜色,输出格式如下:The Plane's color is:颜色在主方法内,定义两个Point(线段的起点和终点)对象、一个Line对象和一个Plane对象,依次从键盘输入两个Point对象的起点、终点坐标和颜色值(Line对象和Plane对象颜色相同),然后定义一个Element类的引用,分别使用该引用调用以上四个对象的display()方法,从而实现多态特性。
主要难度是多态和类的主次之分,分清楚父类Element,及多态的运用就行
第二道是雨刷程序功能扩展设计
也是前面的题目的迭代添加了继承与抽象类的运用,主要为共同属性的提出与父类与子代的共性理解,和第一道一样没有什么难度,主要为继承多态的理解。
第三道航空货运管理系统(类设计)较为偏难
代码规模



**1. **Block Depth 相关数据
含义:表示代码块的嵌套深度,统计了不同嵌套深度下的语句数量。
解读:从数据看,嵌套深度为 1 和 2 时语句较多(分别为 93 和 127 条),说明代码中存在一定量的条件判断、循环等嵌套结构。深度为 3 及以上语句数量大幅减少,整体来看代码块嵌套不算特别深,但仍有优化空间,过深的嵌套会使代码可读性和维护性变差。
2. 方法相关数据(如 list.getDate() 等)
含义:每个方法对应一组四个数值,分别可能代表复杂度、某种度量值、最大深度、调用次数(具体需结合工具定义) 。
解读:多数方法前几个数值较小,如很多方法复杂度为 1,说明大部分方法逻辑不算复杂。但像 list.show() 方法,其数值(7, 24, 5, 18 )相对较大,表明该方法复杂度较高、语句较多、嵌套深度较深且调用次数较多,是代码优化的重点关注对象。
优化的建议:
方法复杂度方面:重点优化 list.show() 等复杂方法,可通过拆分方法、提取重复代码、优化条件判断逻辑等方式降低复杂度。
代码结构方面:进一步审视深度为 1 和 2 的代码块,是否存在可简化或重构的嵌套逻辑,适当减少不必要的嵌套,提升代码的可维护性。

**设计分析: **

  1. 数据聚合
    关联多方信息:list类将客户、发件人、收件人、航班和货物信息整合为一个完整的订单对象。
    数据容器:通过gods[] gods数组存储多个货物,形成订单与货物的一对多关系。
  2. 业务逻辑处理
    载重校验:计算所有货物的总计费重量,并与航班最大载重量比较,决定订单是否可承接。
    费用计算:根据货物的计费重量和费率,计算总运费。
  3. 信息展示
    格式化输出:生成符合题目要求的订单详情文本,包括客户信息、航班信息、货物明细等。
    (一)代码结构与功能概述
    本次作业实现了航空货运管理系统的核心功能,通过分层类设计处理客户、货物、航班及订单信息。
    Main 类:负责读取用户输入数据,包括客户信息、货物详情、航班信息及订单信息,并完成对象的初始化与关联。
    基础类(Person 及其子类):
    Person:封装客户、发件人、收件人的基础信息(编号、姓名、电话、地址)。
    Customer、Sender、Receiver:继承自Person,分别代表客户、发件人、收件人,复用基础信息。
    业务类:
    Goods:存储货物属性(编号、名称、尺寸、重量),并实现计费重量(体积重量与实际重量取较大值)和费率计算逻辑。
    Flight:记录航班基本信息(航班号、起降机场、日期、最大载重量),用于校验订单总重量是否超限。
    List(应命名为Order):聚合订单相关的所有信息(客户、发件人、收件人、航班、货物),负责计算订单总重量、运费,并输出订单详情或载重超限提示。
    输入处理流程:
    读取客户信息并创建Customer对象。
    读取货物数量及每个货物的详细信息,存入Gods数组。
    读取航班信息并创建Flight对象。
    读取订单信息,创建list对象并关联客户、发件人、收件人、航班及货物。
    调用listr.show()方法校验载重、计算费用并输出结果。
    (二)核心算法与逻辑实现
  4. 计费重量与费率计算
    计费重量规则:
    每个货物的计费重量取实际重量与体积重量(长 × 宽 × 高 / 6000)的较大值,公式为:
    java
    if (weight > length * height * width / 6000) {
    计费重量 = weight;
    } else {
    计费重量 = length * height * width / 6000;
    }

费率分档规则:
根据计费重量分四档确定费率,公式为:
java
if (计费重量 < 20) 费率 = 35元/kg;
else if (20 ≤ 计费重量 < 50) 费率 = 30元/kg;
else if (50 ≤ 计费重量 < 100) 费率 = 25元/kg;
else 费率 = 15元/kg;

  1. 航班载重校验
    在list.show()方法中,先计算所有货物的总计费重量,再与航班最大载重量比较:
    java
    double weightAll = sum(货物[i].feizhong());
    if (weightAll > flight.getWeightMax()) {
    输出载重超限提示并终止程序;
    } else {
    计算总运费并输出订单详情;
    }
  2. 订单详情输出逻辑
    格式化输出:按指定格式输出客户信息、航班信息、发件人 / 收件人信息、总重量、总费用及货物明细。
    货物明细处理:遍历货物数组,依次输出每个货物的明细编号、名称、计费重量、费率及运费.
    踩坑心得:
    在输出中的订单总重量为费重,因为这一个在题目中未说明,导致修改了两节晚自习,所以说对题目的理解要细心。
    在收件人,寄件人,客户的类的设计时,其中有相同属性的订单名字编号等属性可以提出,作为父类继承给子类,减少代码的负担。
    未检查数组元素是否初始化:若gods数组中存在null元素,调用feizhong()会触发NullPointerException。
    初始化数组元素:确保循环中正确初始化每个元素。if(flight !=null&&gods != null) { }
    优点与不足:
    优点:基本面向对象设计:使用类和继承(Person基类)组织代码,符合面向对象编程思想。通过封装属性(private字段 +getter/setter)实现数据隐藏。
    业务逻辑完整:实现了航空货运订单的核心流程:客户信息、货物明细、航班信息、费用计算。包含载重超限判断,符合业务需求。
    输入输出处理:使用Scanner实现用户交互,按步骤收集必要信息。输出格式清晰(如表格形式展示货物明细)
    缺点:
  3. 类设计缺陷
    问题:Customer、Sender、Receiver继承自Person但无新增行为,导致类层次冗余。Goods类中number字段含义不明确(既表示货物数量,又作为数组索引)。
    建议:简化类结构,若子类无特殊行为,可直接使用Person类。明确number字段用途,避免语义混淆。
    2.代码重复与可维护性
    问题:字符串格式化(如String.format("%.1f", ...))重复出现。计费逻辑分散在多个方法中,难以维护。
    建议:提取工具方法(如formatWeight())减少重复。将计费规则封装到独立类(如FreightCalculator)中。
    3.空指针风险
    问题:show()方法直接访问flight和gods数组,未检查是否为null。若数组元素未正确初始化,调用方法会触发NullPointerException。
    建议:在关键方法前检查对象是否为null。确保数组元素在使用前已初始化。
    第九次作业
    第一道魔方题:该代码实现魔方属性计算,主类读取输入创建正方体和正棱锥魔方对象,通过抽象类RubikCube定义通用属性与抽象方法,子类实现具体计算。但存在继承关系混乱(如Solid继承RubikCube)、逻辑重复等问题,需优化继承结构、修正算法并简化代码。
    第二道为点线面问题再重构(容器类)为第八次作业的再次迭代与功能插入:该 Java 程序实现几何图形管理系统,通过控制台交互操作。主类读取指令,支持添加点、线、平面,删除指定索引图形,输入 0 结束并显示所有元素。采用抽象类Element定义显示接口,子类Point、Line、Plane实现具体展示。系统结构清晰,支持多态输出。
    第三道NCHU_航空货运管理系统(继承与多态):
    这次作业和上次作业相比只是添加了一些需求,如:客户类型,货物类型,支付方式。并没有太难
    代码规模






    1.方法复杂度
    多数方法复杂度较低,如 person 类的属性访问和设置方法(person.getName() 等),复杂度多为 1 ,意味着逻辑相对简单。但像 gods.Rate() 方法复杂度高达 25 ,说明其内部逻辑复杂,可能包含大量条件判断、循环等操作,是优化重点。
    PTA9.main() 方法复杂度为 2 ,语句数 44 ,调用次数 36 ,作为程序入口,可能承担较多初始化、流程控制等任务,可进一步梳理逻辑。
    2.代码块深度
    从 Block Depth 数据看,深度为 1 和 2 时语句数量较多(分别为 118 和 152 条) ,说明代码中存在较多条件判断、循环等嵌套结构。随着深度增加,语句数量迅速减少,不过整体平均块深度为 1.84 ,仍有优化空间,过深的嵌套会降低代码可读性和可维护性

设计分析:

  1. 类结构与职责划分
    核心类功能:
    person及其子类(customer、sender、receiver):封装用户基础信息(姓名、电话、地址等),通过继承实现不同角色的差异化(如customer有类型属性type)。
    gods与godscharacteristic:gods代表货物集合,godscharacteristic描述单个货物的属性(尺寸、重量等),通过聚合关系(List)管理货物明细。
    flight:封装航班信息(航班号、起降机场、载重上限等),用于校验订单总重量是否超限。
    list(订单类):整合所有业务对象(客户、货物、航班等),负责计算运费、应用折扣及展示订单信息,是业务逻辑的核心。
    关系设计:
    继承关系:customer、sender、receiver继承自person,符合 “is-a” 逻辑(如客户是一种人)。
    聚合关系:gods包含多个godscharacteristic,list包含customer、gods、flight等对象,体现整体与部分的关系。
  2. 业务逻辑流程
    数据输入:通过Scanner从控制台依次读取客户、货物、航班、订单等信息,按对象属性逐个设置。
    核心计算:
    计费重量:在gods类中通过maxweight方法比较实际重量与体积重量(长 × 宽 × 高 / 6000),取较大值作为计费重量。
    费率计算:根据货物类型(Normal/Expedite/Dangerous)和计费重量区间,在gods.Rate()中设置不同费率。
    总金额与折扣:在list.calculate()中汇总所有货物费用,再根据客户类型(个人 / 企业)应用折扣(9 折 / 8 折)。
    结果校验与输出:
    校验订单总重量是否超过航班载重上限,若超限则提示错误。
    通过list.show()格式化输出订单详情,包括客户信息、货物明细及支付金额。
    优缺点;
    优点
  3. 面向对象设计思想的应用
    封装性:各对象的属性通过private修饰,通过getter/setter访问,符合封装原则(如person类的属性隐藏)。
    继承与多态:子类继承person类的公共属性(姓名、电话等),避免代码重复(如sender和receiver无需重复定义基础信息)。
    单一职责原则:每个类职责明确,如gods类专注于货物计费逻辑,list类负责订单整合与计算,代码结构清晰。
  4. 业务逻辑完整性
    计费规则覆盖全面:考虑了实际重量与体积重量的比较、不同货物类型的费率差异、客户类型折扣,以及支付方式的区分(支付宝 / 微信 / 现金)。
    边界校验:在show()方法中校验航班载重上限,防止无效订单提交,增强了业务逻辑的健壮性。
  5. 代码可读性与可维护性
    命名规范:类名(如godscharacteristic应为GoodsCharacteristic,驼峰命名更规范)、方法名(calculate、show)表意清晰。
    注释与结构:部分方法(如gods.maxweight)通过逻辑注释说明计算规则,便于理解;代码结构按类分层,层次分明。
    缺点:
    空指针风险:
    gods类的characteristics列表在addCharacteristic中未初始化时会创建新列表,但在其他场景(如未调用addCharacteristic直接取值)可能引发NullPointerException。
    list类的customer、sender等属性未检查是否为null,若未正确设置可能导致后续调用getName()等方法时崩溃。
    逻辑耦合与优化空间
    list类职责过重:
    list类不仅负责订单数据整合,还承担了运费计算、折扣逻辑、输出展示等功能,违反 “单一职责原则”。建议将计算逻辑(如calculate)拆分到独立的服务类(如OrderService)中,提高可维护性。

改进建议:

  1. 修正父类与子类构造方法
    问题:子类未调用父类带参数的构造方法,导致属性初始化不一致。
    改进:在子类中通过super()传递参数,统一初始化父类属性。
  2. 问题:职责过重(如list类)
    改进:将list中的计算逻辑拆分到listrCalculator工具类中。
  3. 空指针预
    问题:未初始化的List或未赋值的对象可能引发NullPointerException。
    改进:在类初始化时创建空集合,或在使用前检查null。
  4. 问题:业务逻辑繁杂Gods.Rate()方法中通过大量if-else判断货物类型和重量区间,耦合度高。
    改进: 使用策略模式解耦费率计算定义费率计算策略接口,不同货物类型实现该接口。
    总结:
    (一)缺点的发现:
    代码整体能够完成题目及业务的要求,但是对继承和多态接口的,分工及运用还是不太清楚什么时候用继承,什么时候用多态,什么时候用接口,业务逻辑的耦合性不是特别的完美,还需要进一步的强化,以达到业务逻辑的水平,代码的开闭原则也不是特别的完美。
    (二)代码逻辑能力的提升:
    从第八次作业的航空货运管理系统,到第九次作业的航空货运管理系统,逐步熟练继承,多态以及接口的运用,并将其用于作业当中,逐步提高自己对面向程序设计这门课的理解。
    (三)未来学习的方向
    未来将会学习各种类与类的各种模式,通过这些模式将各个类相关连起来,使得面向程序设计这门课更加重要
posted @ 2025-05-20 19:16  洛L0  阅读(23)  评论(0)    收藏  举报