第三次博客作业——总结
前言PTA作业:
题目结构科学合理,前几道题聚焦基础语法与常见逻辑结构,像耐心的引路人,带我熟悉 Java 基本语法与类结构设计,夯实编程根基。而最后一题往往是 “压轴难题”,涵盖类的继承、接口实现、复杂对象管理等面向对象设计思维。在攻克难题的过程中,我不仅提升了语法熟练度,更学会从设计的合理性、扩展性等角度深入思考,让代码不再只是实现功能的工具,而是具备优化潜力的作品。
实验:
通过实验,我深刻领悟到软件开发中 “模块化、组件化” 构建的重要性。虽然过程中工作量不小,但每完成一个模块,每解决一个问题,都让我的代码组织能力得到切实提升,也对软件开发流程有了更直观的认识。
线下课程:
面向对象设计原则、常见设计模式以及 GUI 编程的基本概念等内容,虽不像实际操作那样能即刻看到成果,但它们如同代码世界的 “底层框架”,为我构建起对 Java 编程体系的整体认知。这些理论知识如同明灯,在后续实践中指引方向,让我在编写代码时,不仅知其然,更知其所以然,为未来的编程之路打下坚实的理论基础。
面向对象技术总结
一、面向对象设计核心概念回顾
面向对象编程(OOP)的本质是将现实世界的问题拆解为具有独立职责的 “对象”,通过对象间的交互实现系统功能。其核心概念包括:
封装(Encapsulation)
将数据(属性)和操作数据的方法(行为)封装在类中,通过访问修饰符(如private)隐藏内部实现细节,仅暴露必要的接口。
案例体现:在Order类中,所有属性(如customerName、cargoCount)均设为private,仅通过公共方法(如getTotalWeight())提供访问接口,避免外部直接修改数据导致逻辑混乱。
继承(Inheritance)
通过子类继承父类的属性和方法,实现代码复用和类型扩展。
案例思考:若系统需要区分 “普通订单” 和 “加急订单”,可通过继承Order类创建子类,重写运费计算或配送逻辑。
多态(Polymorphism)
同一接口在不同实现类中表现出不同行为,通过方法重载或重写实现。
案例体现:Cargo类的calculateFreight()方法根据客户类型(customerType)计算不同折扣,若未来新增客户类型(如 “企业客户”),可通过多态扩展而不修改原有代码。
接口与抽象类(Interface & Abstract Class)
接口定义行为契约,抽象类提供部分实现,两者均用于解耦接口与实现。
案例思考:可定义IPayment接口规范支付行为,让Order类依赖接口而非具体支付实现(如支付宝、微信支付),符合依赖倒置原则。
二、SOLID 设计原则在案例中的应用
SOLID 原则是面向对象设计的核心准则,用于提升代码的可维护性和可扩展性:
单一职责原则(Single Responsibility Principle, SRP)
一个类仅负责一项职责。
案例分析:
Order类负责订单信息管理、货物计算、信息展示等职责,略显复杂,可进一步拆分出OrderInfoManager(管理订单基础信息)和OrderCalculator(负责运费计算),使职责更单一。
Cargo类专注于货物属性计算(如计费重量、费率),符合 SRP。
开闭原则(Open-Closed Principle, OCP)
软件实体应对扩展开放,对修改关闭。
案例改进点:
Cargo类中通过if-else判断货物名称设置费率(如 “发电机”“信号发生器”),违反 OCP。优化方案:定义CargoType接口,不同货物类型实现接口并自定义费率计算逻辑,Cargo类依赖接口而非具体类型。
里氏替换原则(Liskov Substitution Principle, LSP)
子类应能替换父类且不破坏程序原有逻辑。
案例思考:若创建DangerousCargo(危险货物)子类继承Cargo,需确保其重写的calculateFreight()方法符合父类契约(如返回值类型、参数不变)。
接口隔离原则(Interface Segregation Principle, ISP)
客户端不依赖其不需要的接口。
案例应用:若系统需要区分 “可追踪订单” 和 “普通订单”,可定义ITrackable接口,仅让需要追踪功能的订单类实现该接口,避免接口臃肿。
依赖倒置原则(Dependency Inversion Principle, DIP)
高层模块不依赖低层模块,两者均依赖抽象。
案例改进点:
Order类直接创建Cargo数组(this.cargos = new Cargo),违反 DIP。优化方案:通过工厂模式(CargoFactory)创建Cargo对象,使Order依赖抽象工厂而非具体实现。
三、货运订单系统设计的核心架构分析
以之前的类图和代码为例,系统设计的关键逻辑包括:
类间关系设计
组合关系(Composition):Order与Cargo通过组合关联(Cargo[] cargos),表示 “订单由货物组成”,货物生命周期依赖于订单,符合现实业务逻辑。
依赖关系:Order依赖Scanner进行输入处理,Cargo依赖Order的客户类型计算运费,依赖方向清晰。
核心功能流程
订单创建:通过Order构造函数读取输入数据,校验合法性(如货物数量、重量的数字格式),创建Cargo对象数组。
运费计算:Cargo根据货物类型和客户类型计算计费重量与折扣,Order汇总所有货物运费。
超载检查:Order通过isExceedMaxWeight()方法对比总重量与航班最大载重,决定是否显示订单信息。
可优化点
代码复用:Order和Cargo中的输入校验逻辑(如readDouble()方法)可提取为工具类(InputValidator),避免重复代码。
异常处理:当前通过循环和try-catch处理输入错误,可封装为自定义异常(如InvalidInputException),使错误处理更规范。
四、面向对象设计的实践感悟
从 “过程” 到 “对象” 的思维转变
传统编程关注 “如何做”(流程),面向对象关注 “谁来做”(对象职责)。例如,计算运费的逻辑不应是独立函数,而应属于Cargo对象的行为,符合 “数据与行为绑定” 的思想。
设计原则的平衡艺术
过度追求原则可能导致设计复杂化(如拆分过多类),需根据需求规模权衡。例如,小型系统中Order类可暂不拆分职责,待需求扩展后再重构。
面向对象与设计模式的结合
设计模式是面向对象原则的具体应用。例如:
用工厂模式(Factory Pattern)解耦对象创建,符合 DIP;
用策略模式(Strategy Pattern)封装不同运费计算规则,符合 OCP 和 SRP。
五、总结
面向对象设计的核心是 “抽象现实问题为对象,通过对象协作解决问题”。通过本次实践,深刻体会到:
封装确保数据安全,继承与多态实现代码复用,接口隔离降低耦合;
SOLID 原则是避免代码 “腐化” 的指南针,需在开发中时刻牢记;
优秀的面向对象设计不是一蹴而就的,而是通过持续重构(如提取接口、拆分类)逐步优化的结果。
采坑心得
典型场景1:
为复用Order类中的客户信息字段,创建VIPOrder、GroupOrder等子类,结果发现:
父类的某些方法(如displayOrderInfo())在子类中需完全重写;
子类引入新字段(如VIPOrder的折扣等级)导致父类字段冗余;
继承层级过深,修改父类可能影响所有子类。
惨痛教训:
违背 LSP 原则:子类无法完全替代父类,例如VIPOrder的运费计算逻辑与父类差异过大;
代码耦合:子类与父类强绑定,父类修改可能引发子类崩溃;
维护噩梦:继承层级成为 “技术债”,后续需求变更需谨慎评估对整个继承树的影响。
避坑指南:
优先组合,而非继承:通过Order包含Customer对象(组合)替代继承,如:
点击查看代码public class VIPOrder {
private Order baseOrder;// 组合基础订单
private VipInfo vipInfo;// 扩展VIP信息
// 通过委托实现方法复用
}接口隔离:定义VIPOrder实现Discountable接口,而非继承Order;
使用模板方法模式:若必须继承,通过抽象父类定义骨架方法(如订单处理流程),子类仅实现差异化部分。
典型场景2:
Order类直接依赖Scanner进行输入,导致单元测试无法脱离控制台;
Cargo类的calculateFreight()方法依赖Order的customerType字段,形成双向依赖;
全局状态管理混乱,多个类共享静态变量(如PaymentMethod列表),修改一处影响多处。
惨痛教训:
测试困难:无法独立测试Order的创建逻辑,必须模拟用户输入;
扩展性差:若需支持新的输入方式(如文件读取),需修改Order类;
线程安全问题:共享静态变量在多线程环境下引发竞态条件。
避坑指南:
依赖注入(DI):通过构造函数注入InputReader接口,而非直接依赖Scanner:
点击查看代码public class Order {
private InputReader reader;
public Order(InputReader reader) {
this.reader = reader;
}
}单向依赖:重构Cargo的运费计算逻辑,使其仅依赖客户类型参数,而非整个Order对象;
使用单例模式管理全局状态:将PaymentMethod列表封装在单例类中,提供线程安全的访问方法。
改进建议及总结:
————面向对象设计的 “道” 与 “术”
道(思维层面):
面向对象的本质是 “模拟现实世界的协作关系”,将问题拆解为职责清晰的对象,通过对象间的消息传递解决问题,而非面向过程的 “步骤堆砌”。
术(实践层面):
用封装保护数据,用多态应对变化,用接口隔离依赖;
牢记 SOLID 原则,但不盲目追求,根据项目规模灵活取舍;
持续重构是保持代码活力的关键,“烂代码” 不是写出来的,是积累出来的。
一句话感悟:
“面向对象设计就像组装乐高积木 —— 每个类是一个独立模块,通过标准化接口(接口 / 抽象类)与其他模块协作,既能快速搭建简单功能,也能扩展成复杂系统。”
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页:
[1]