第二次博客作业
第八次作业题集
- 单一职责原则
Cargo类:仅负责货物基础属性和计费重量计算。
Flight{insert_element_17_}类:仅管理航班状态和载重校验。
Paymen{insert_element_18_}t类:仅处理支付折扣逻辑。 - 里氏代换原则
所有货物子类(GeneralCargo、DangerousCargo等)均继承自Cargo,可替换父类对象使用,保证多态性。 - 开闭原则
新增货物类型(如 “贵重货物”)时,只需创建新子类继承Cargo并实现费率计算,无需修改现有代码。 - 合成复用原则
Order类通过组合Customer、Flight、Cargo对象实现功能,而非继承,提高代码复用性。 - 依赖倒转原则
Payment抽象类定义支付接口,Order类依赖抽象而非具体实现(如WeChatPayment),降低耦合度。
五、扩展与优化方向
货物类型扩展:根据题目提示,可新增ValuableCa{insert_element_24_}rgo子类,实现独立费率规则。
支付方式扩展:新增AlipayPayment、CashPayment子类,分别实现不同折扣逻辑(如集团用户 8 折)。
异常处理增强:对输入格式错误(如非数字字符)添加try-catch捕获InputMismatchException。
数据持久化:使用文件或数据库存储订单历史,而非仅内存处理。
在完成这段代码的过程中,对面向对象编程的核心概念有了更系统的认知,尤其是继承与多态机制的实际运用,通过代码实践理清了几个关键知识点:
-
抽象类与多态的本质
通过定义Element抽象类强制子类实现display()方法,理解了抽象类作为 “模板” 的作用 —— 它规定了子类必须具备的行为(如显示功能),但将具体实现留给子类。当用Element引用指向不同子类对象(如Point、Line)时,真正体会到多态的核心:父类引用在运行时动态绑定子类方法,这种 “统一接口、不同实现” 的设计,让代码结构更灵活,例如新增Plane类时只需继承Element并实现方法,无需修改主程序调用逻辑。 -
继承体系的职责划分
设计Point、Line、Plane子类时,明确了继承不仅是代码复用,更是 “类型归属” 的定义。例如Line类组合Point对象(起点 / 终点)而非直接继承,体现了 “has-a” 关系(组合)与 “is-a” 关系(继承)的区别 ——组合更适合描述对象间的整体 - 部分关系,而继承用于类型扩展。这种设计让Line类专注于线段特有的属性(颜色、长度计算),符合单一职责原则。 -
方法重写的规则与细节
实现子类display()时,通过@Override注解确保方法签名与父类一致,避免因拼写错误导致的 “隐藏父类方法” 问题。例如Point类的格式化输出(%.2f,%.2f),需要严格匹配题目要求的输出格式,这让我注意到重写方法时需完全遵循父类约定的契约,包括返回值类型、参数列表和访问权限。 -
输入输出的格式化控制
使用Scanner读取输入时,通过nextDouble()和next()的组合处理不同类型数据,理解了输入流的读取顺序对数据准确性的影响。输出时通过String.format("%.2f", data)精确控制小数位数,掌握了 Java 格式化字符串的用法 ——数值格式化不仅是功能需求,更是用户体验的重要部分,需严格对照样例确保格式一致性。 -
对象组合与依赖关系
Line类依赖Point对象计算长度,Plane类仅持有颜色属性,这种设计让不同类的职责清晰分离。例如线段长度的计算公式√[(x2-x1)²+(y2-y1)²],通过调用Point的getX()/getY()方法获取坐标,体现了 ** 对象间通过接口协作(而非直接操作属性)** 的封装思想,增强了代码的可维护性。 -
多态的实际应用场景
主程序中通过统一的Element引用调用不同对象的display()方法,无需为每个子类编写独立的调用逻辑,这让我明白多态的核心价值:减少代码冗余,提高可扩展性。例如未来新增Circle类时,只需继承Element并实现display(),主程序代码无需任何修改,真正体现了 “开闭原则”。
通过这次实践,对 Java 面向对象的 “抽象 - 继承 - 多态” 体系有了从理论到实操的完整认知,尤其是在设计类层次时,学会了从 “职责分离” 和 “扩展能力” 角度思考。代码调试过程中暴露的细节问题(如输入顺序错误、格式化符号遗漏),也强化了对编程严谨性的理解 ——每一个看似简单的功能,都需要精准的逻辑控制和细节处理。这些经验不仅适用于当前案例,也为后续复杂系统的设计奠定了基础。
第九次作业题集
(前言) -
抽象类与继承
抽象类:Cargo定义抽象方法getRate(),强制子类实现差异化逻辑(如NormalCargo/ExpediteCargo)
继承层次:通过继承复用calculateVolumeWeight()等通用逻辑,符合 DRY 原则 -
多态实现
父类引用指向子类对象:List统一存储不同类型货物,运行时动态调用子类方法
方法重写:子类通过@Override注解实现父类抽象方法(如ExpediteCargo.getRate())
二、设计模式与原则 -
单一职责原则
Cargo类:仅负责货物属性与计费逻辑
Flight类:仅管理航班载重校验
Order类:协调订单创建与费用计算 -
开闭原则
新增货物类型(如ValuableCargo)只需继承Cargo,无需修改现有代码
支付方式扩展(如UnionPay)通过新增子类实现,符合扩展开放、修改关闭 -
合成复用原则
Order类通过组合Customer、Flight、Cargo对象实现功能,避免继承带来的耦合
三、核心业务逻辑 -
计费规则实现
体积重量计算:(长×宽×高)/6000(符合航空货运行业标准)
阶梯费率:根据货物类型和重量区间动态计算(如加急货物20kg以下费率60)
四、输入输出处理 -
Scanner 输入解析
按顺序读取不同类型数据(nextDouble()/next())
循环读取可变数量的货物信息
五、集合与流操作 -
List 集合
存储多个Cargo对象,支持动态扩展 -
Stream API
计算总重量和总费用,简化集合操作
六、异常处理与边界条件 -
载重校验
在订单创建前检查flight.isLoadValid(totalWeight)
超限则输出错误信息并终止程序 -
输入验证
假设输入格式合法(题目未要求异常处理)
实际应用中需添加try-catch处理非数字输入等异常
一、抽象类与多态:从困惑到顿悟的蜕变
当第一次面对Cargo抽象类的设计时,我的内心充满了问号 ——“为什么不能直接用普通类?” 直到我尝试在Order类中处理不同货物类型时,才突然意识到:抽象类就像是一把精准的手术刀,它帮我把 “共性”(如体积重量计算)和 “个性”(费率规则)完美分离!当我写下Cargo cargo = new ExpediteCargo()时,那种 “父类引用指向子类对象” 的魔法,让我忍不住拍桌惊叹:原来多态真的能让代码如此优雅!
二、阶梯费率计算:与数学公式的博弈
计算阶梯费率那段代码,绝对是整个项目的 “硬核关卡”!看着需求文档里密密麻麻的费率表,我的大脑瞬间进入 “数学考试” 模式。每写一个if-else分支都要反复验算,手指在计算器上敲得飞快,生怕漏掉 0.1kg 的精度差。当最终通过getRate()方法把这些复杂规则封装得严丝合缝时,那种感觉就像解开了一道奥数题 ——痛并快乐着!
三、输入输出格式化:细节控的终极挑战
“保留一位小数”“对齐货物明细表格” 这些需求,看似简单却暗藏杀机!我对着控制台输出反复比对样例,眼睛瞪得像铜铃,终于发现是String.format里的\t和%.1f没配对好。那一刻,我深刻体会到:编程真的是个 “细节决定成败” 的游戏,一个字符的偏差都可能让整个输出乱成一团!
四、设计原则:代码背后的隐形翅膀
当我用单一职责原则把Flight类的载重校验和Order类的费用计算分开时,突然发现代码变得前所未有的清爽。这种 “高内聚、低耦合” 的设计带来的愉悦感,就像整理好了一间杂乱的房间 ——每个类都在它该在的位置,各司其职,和谐共处。而开闭原则让我在新增ValuableCargo时,只需要简单继承Cargo类,完全不用动其他代码,这种 “零改动扩展” 的体验,简直不要太爽!
五、调试时刻:从崩溃到狂喜的过山车
当我第一次运行程序就看到 “超载错误” 提示时,心里一阵窃喜 ——“看来载重校验逻辑写对了!” 但当输入合法数据却得到错误的费用计算结果时,我的笑容瞬间凝固。接下来的两小时,我像个侦探一样在代码里逐行排查,最后发现是discount计算时把 “个人” 和 “集团” 的折扣系数写反了。当修正后看到正确输出的那一刻,我兴奋得差点从椅子上跳起来,那种感觉就像找到了丢失已久的宝藏

浙公网安备 33010602011771号