PTA题目集8-9总结性Blog
- 前言:
知识点总结:
抽象类
包含抽象方法的类(需 abstract 修饰),强制子类实现抽象方法,可包含非抽象方法实现代码复用。
接口
完全抽象的行为(interface),所有方法默认 public abstract,实现类需提供具体逻辑。
继承
子类通过 extends 继承父类,复用属性和方法,实现 “is-a” 关系(如 Plane extends Element)。
多态
基类引用指向子类对象,通过统一接口调用不同实现(依赖方法重写 @Override)。
封装
成员变量 private 修饰,通过 getter/setter 控制访问,构造方法初始化对象状态。
1. 开闭原则(OCP)
*定义:
软件实体(类,模块,函数等)应支持通过扩展实现功能新增,而无需修改现有代码。
*核心思想:
扩展:通过新增子类、接口实现类或配置等方式扩展功能。
封闭:已稳定的代码逻辑不允许直接修改,避免变更风险。
*作用:
降低修改现有代码引发的潜在bug风险。提高系统可扩展性,适应需求变化(如新增功能、需求调整)。
2. 单一职责原则(SRP)
*定义:
每个类/模块/函数仅负责单一职责,只需要完成一个任务。
*核心思想:
职责分离:避免一个类承担多个独立功能(如将 “数据读取” 与 “业务计算” 分离)。
高内聚:类的功能应高度集中,确保修改某一职责时不影响其他职责。
*作用:
降低类的复杂度,提高代码可读性。
缩小变更影响范围,提升维护效率。
3. 里氏替换原则(LSP)
*定义:
子类必须能完全替换其父类,且程序逻辑保持不变(即子类行为需符合父类预期)。
*核心思想:
子类需遵循父类的接口契约(方法签名、前置 / 后置条件、不变式)。
子类可扩展功能,但不能削弱父类原有功能(如子类方法不能抛出父类未声明的异常)。
*作用:
确保多态机制的可靠性,避免子类破坏系统原有逻辑。
保障继承体系的稳定性,支持透明替换(如用子类对象替代父类对象时程序正常运行)。
4. 依赖倒置原则(DIP)
*定义:
高层模块不应依赖低层模块,两者应依赖抽象(接口/抽象类)。抽象不应依赖具体实现,具体实现应依赖抽象。
*核心思想:
解耦高层逻辑与低层实现,通过抽象层建立联系。面向接口编程,而非面向实现编程。
*作用:
降低模块间耦合度,使高层逻辑与低层实现可独立演进。
提高系统灵活性,便于替换不同实现(如切换雨刷型号或货物类型策略)。
题量及难度分析:
这次PTA题目集的难度相较于之前的题目集,难度明显下降,题目的量也没有那么大了,但是题目的代码量并没有减少,题目还是那个题目,但是我早已不是那个我了,所以相较于上一次的题目集而言,这一次我的应对能力得到了不小的提升。
2. 设计与分析:
1.点线面问题:
抽象类Element:定义图形元素的公共接口display()。
子类:
Point:表示坐标点,输出坐标(如(x,y))。
Line:表示线段,包含两个Point对象,计算长度并输出颜色、端点坐标和长度。
Plane:表示平面,输出颜色。
核心逻辑:通过多态实现统一调用display(),主函数直接创建对象并验证坐标范围。
2.雨刷程序问题:
组件交互:
Lever:控制雨刷模式(停止、间歇、低速等),位置范围由WiperSystem定义。
Dial:调节同模式下的速度档位,范围由WiperSystem定义。
Agent:统一处理杠杆 / 拨盘的操作(如handleLeverUp),并通过WiperSystem计算结果。
3.魔方问题:
RubikCube抽象魔方的 “外观”(颜色、阶数)和 “几何行为”(表面积 / 体积)。
Solid抽象基础立体(正方体 / 正三棱锥)的计算逻辑,通过组合模式嵌入魔方(RubikCube.solid),体现 “魔方由基础立体构成” 的物理结构。
4.航天货物运输问题:
以下是第一题的代码类图:(类设计)

核心类:
Cargo(货物):具体类,包含计费重量、费率计算逻辑(calculateRate/calculateFee)。
Order(订单):聚合Customer、Flight、AddressInfo和Cargo列表,计算总重量和总费用。
Customer/Flight/AddressInfo:实体类,封装基础信息(客户、航班、地址)。
设计特点
关系:
Order与Cargo为聚合关系(List
Order依赖Customer、Flight、AddressInfo(通过构造方法传入)。
面向过程思维:
Cargo类直接实现计费逻辑,Order类通过循环调用Cargo方法计算总费用,逻辑集中在具体类中。
无抽象层,所有类均为具体实现(如Cargo非抽象类)。
数据封装:
成员变量private修饰,通过getter/setter访问。
输入输出:
Main类处理输入输出(Scanner读取数据、printf输出结果)
扩展性不足:
新增货物类型(如危险货物)需修改Cargo类,违反开闭原则。用户折扣、支付方式等扩展需求需修改Order类,代码耦合度高。

方法复杂度:
Main.main()方法因混合输入、业务逻辑和输出,导致圈复杂度(10)和嵌套深度(67)极高,违反单一职责原则,维护困难;DangerousCargo.calculateRate()的多重if-else(圈复杂度 5)硬编码费率,扩展性差。这些问题使代码可读性低、耦合度高,难以应对需求变化(如新增货物类型或费率规则)。
第二题类图分析:(继承与多态)

核心类
Cargo(货物):
具体类,直接实现计费逻辑(calculateRate/calculateFee),通过继承扩展(如DangerousCargo、ExpediteCargo)。
设计特点
关系与依赖:
聚合关系:Order聚合Cargo(has-a),依赖Customer、Flight(构造方法注入),结构清晰但扩展性弱(如Order无法动态调整Cargo策略)。
面向过程残留:业务逻辑集中在具体类(Cargo计算费率,Order累加费用),无抽象层(如无CargoStrategy接口),导致新增需求需修改现有类(如ExpediteCargo继承Cargo,基类逻辑变动影响子类)。
数据与输入输出:
封装性:成员变量private,通过getter访问,符合封装;但Main类混合输入输出与业务逻辑(Scanner读取、printf输出),未分离 UI 与业务层,耦合度高。
扩展性不足:
货物类型:新增类型需修改Cargo继承体系(如ExpediteCargo扩展Cargo),基类非抽象(Cargo含具体方法),子类易受基类变动影响。
业务规则:用户折扣、支付方式等需在Order中添加条件判断(如if (userType.equals("VIP"))),违反单一职责,复杂度上升。

方法复杂度:
Main.main()过载:
圈复杂度 10(高),包含输入解析、业务逻辑(订单计算)、输出格式化,职责不分离,导致代码冗长(199 行)、嵌套深(最大块深度 5),维护困难。
成因:混合 UI 与业务逻辑,无抽象层,硬编码条件(如货物类型判断)。
Cargo类扩展性不足:
计费逻辑(calculateRate)直接实现,新增货物类型(如ExpediteCargo)需修改基类,违反开闭原则,间接增加main方法的分支复杂度。
3.踩坑心得:
抽象层缺失:初期代码未定义抽象接口,新增功能需改核心类(如点线面代码 1 无集合管理,代码 5 才优化),魔方继承冗余(如RegularPyramidCube继承SquareCube)。
硬编码:雨刷杠杆名、货运费率硬编码,新增规则需改多处(如Table2的case 5),易出错。
心得体会
抽象是扩展关键:通过抽象类 / 接口(如Element、RateStrategy)定义契约,子类实现差异,避免改核心(如点线面新增图形只需继承Element)。
职责分离提升可维护:拆分 UI、业务、数据层(如InputHandler/OrderService),降低耦合(如航空货运代码模块化后main更简洁)。
设计模式解场景问题:中介者(雨刷组件交互)、策略(费率计算)、组合(魔方层堆叠)等模式,适配场景,增强扩展性(如货运新增费率策略无需改基类)。
改进建议:
在编码时,点线面问题可以设计统一的图形创建方式,方便后续添加新图形类型;雨刷系统把不同速度计算逻辑分开,以后修改规则直接新增方法就行;魔方问题要记录每个状态,方便扩展不同的还原算法;航空货运系统分模块管理功能,用数据库存储数据更可靠。平时写代码要加清楚注释,用工具自动检查错误,定期整理复杂代码,让系统长期保持容易维护和扩展的状态,每次改进都为后续功能升级打好基础。
总结:
以上内容围绕不同代码案例(点线面图形、雨刷系统、魔方、航空货运等)展开分析,核心问题集中在代码复杂度高、扩展性不足、职责耦合等方面。解决方法包括运用抽象类 / 接口分离共性逻辑(如Element抽象类)、通过策略模式解耦条件分支(如货运费率计算)、利用中介者模式协调组件交互(如雨刷系统Agent),以及模块化拆分 UI 与业务逻辑(如将Main的输入输出独立为工具类)。设计模式的应用(策略、中介者、组合等)和工具辅助优化(SonarQube 监控复杂度、IDE 重构)是提升代码质量的关键。踩坑心得强调抽象层先行、职责分离的重要性,避免硬编码和混合逻辑。未来改进方向指向更系统的架构优化(如微服务、持久化)、规范文档和持续集成测试,确保代码长期可维护、易扩展,形成 “设计 - 优化 - 迭代” 的良性开发流程。

浙公网安备 33010602011771号