面向对象程序设计课程总结
目录
前言
回顾这一学期的 Java 面向对象课程学习历程,丰富多样的教学环节构成了充实的学习体验。Blog 作业、PTA 作业、实验、线上课程与线下课程相互交织,共同搭建起知识的框架。
从工作量来看,每周固定一次PTA作业,大概3-5题,难度不是非常大,紧密围绕课程核心内容,在实践中将知识吃透,让我们不只是听懂了,更是学会了。两周一次的实验,难度比PTA稍微大了一点,也在可接受范围内,将我们所学的知识真正结合起来,实验的内容也是比较有趣的。还有Blog作业,对PTA中两次比较难的题目进行分析总结,要求不是很多,但能让我们真正吃透这两题。线上课程通过生动的讲解和丰富的案例,为线下课程奠定了良好基础,线下课程则在理论基础上,引导我们深入探讨和实践。整体而言,课程设计合理,工作量与难度相匹配,让我在挑战中不断成长。
面向对象技术总结
封装
以题目集7的第一题销售步枪为例。在步枪销售程序中,封装原则的应用贯穿于整个系统设计,通过将数据与操作逻辑紧密绑定并隐藏实现细节,构建出高内聚、低耦合的模块化架构。以销售订单管理为例,SalesOrder类不仅封装了枪机、枪托、枪管的销售数量,还将生产限额验证、销售额计算等业务逻辑封装在内,外部调用者只需通过setSalesCounts()和calculateTotalAmount()等方法与其交互,无需关心内部实现。这种设计使得订单处理流程与组件价格、佣金算法等细节解耦,当密苏里州调整组件生产成本导致价格变动时,只需修改RifleComponent类的初始化逻辑,其他模块不受影响。
在佣金计算模块,CommissionCalculator类将复杂的阶梯式提成算法封装为单一公共方法calculateCommission(),调用者只需传入销售额即可获得结果,无需了解具体计算逻辑。这种封装屏蔽了业务规则的复杂性,当销售商与厂商协商调整佣金比例时,开发人员可以专注于该类内部实现的修改,而不会对订单处理或报告生成模块产生涟漪效应。类似地,SalesReport类将销售数据汇总与格式化输出逻辑封装,确保系统输出符合税务部门要求的标准报表格式,即使未来报表样式发生变化,也能在不影响核心业务逻辑的前提下独立演进。
通过这种分层封装,系统各部分如同精密运转的机械零件,每个类都像一个独立的黑盒,仅通过定义清晰的接口与外部交互。例如,客户端代码在创建SalesOrder对象后,只需调用其公共方法设置销售数量并计算总额,无需知道内部如何验证生产限额或处理不完整订单。这种抽象层次的提升不仅简化了代码的使用方式,更重要的是建立了坚实的防御机制 —— 当用户输入非法数据时,SalesOrder类内部的验证逻辑会立即抛出异常,阻止错误数据进入系统,确保数据完整性。这种将数据保护与业务逻辑封装在同一实体中的做法,使得系统在面对频繁的需求变更时仍能保持稳定,充分体现了面向对象编程中封装带来的安全性与可维护性优势。
继承与多态
从PTA题目集8开始考察继承与多态。在点线面问题的重构中,继承机制通过引入抽象基类Element实现了代码的统一抽象。该基类声明了抽象方法display(),强制Point、Line和Plane子类提供具体实现。这种设计使客户端代码可通过基类引用动态调用不同子类的行为,例如当element引用指向Point对象时,display()输出坐标信息;指向Line对象时,则输出线段的颜色、起点终点坐标及长度。通过这种方式,系统实现了对不同图形的统一处理,当需要新增图形类型(如圆形)时,只需继承Element类并实现display()方法,无需修改现有代码结构,体现了继承在代码扩展性方面的优势。多态通过抽象基类Element的引用实现动态行为绑定。当基类引用element分别指向Point、Line和Plane对象时,相同的display()方法调用会产生不同的执行结果:指向Point对象时输出坐标(x,y),指向Line对象时输出线段颜色、起止坐标及长度,指向Plane对象时输出面的颜色。这种机制的核心在于Element类将display()声明为抽象方法,强制子类重写实现特定逻辑,而客户端代码无需关心对象具体类型,仅通过基类接口即可完成操作。例如,在主方法中通过element = line将引用指向线段对象后,调用display()会自动执行Line类中重写的方法,计算线段长度并按格式输出,体现了 “同一接口,不同实现” 的多态本质。
在魔方问题中,继承与组合机制的结合构建了灵活的立体图形系统。基类RubikCube定义了魔方的公共属性(颜色、阶数)和抽象方法(表面积、体积计算),而SquareCube和RegularPyramidCube子类则通过组合基础几何体对象(Cube和RegularPyramid)实现具体计算逻辑。例如,正方体魔方的表面积计算依赖于基础正方体的表面积公式,并结合阶数进行扩展。这种设计不仅复用了基础几何体的计算逻辑,还通过多态机制使display()方法能够统一处理不同类型的魔方,客户端代码无需关心具体魔方类型,只需通过基类接口调用相应方法即可。当系统需要支持新的魔方类型(如正八面体魔方)时,只需创建新的子类并实现抽象方法,充分体现了继承与多态在构建可扩展系统中的价值。通过这种层次化设计,系统各部分职责清晰,上层模块依赖抽象而非具体实现,符合依赖倒置原则,使代码在面对需求变化时保持稳定。多态则通过基类RubikCube的抽象方法与子类重写实现。RubikCube定义了getSurfaceArea()和getVolume()抽象方法,SquareCube和RegularPyramidCube分别根据几何体特性重写这些方法。当display()方法接收RubikCube类型参数时,会根据实际引用的对象类型调用对应的计算逻辑:若引用指向SquareCube,则按正方体魔方公式计算表面积(6 * layer² * side²)和体积(layer³ * side³);若指向RegularPyramidCube,则按正三棱锥魔方的公式计算(表面积涉及底面和侧面三角形面积,体积为(layer³ * side³ * √2)/12)。这种设计使得display()方法无需通过条件判断区分魔方类型,直接通过多态调用实现差异化处理,例如代码中cube.getSurfaceArea()会根据cube实际引用的子类对象,动态执行对应的计算逻辑,确保输出结果符合具体魔方类型的特性,同时保持客户端代码的简洁性与扩展性。
抽象类与接口
在 “动物装入电器” 实验中,抽象类与接口的运用为程序设计带来了清晰的结构与强大的扩展性。实验模拟将不同动物放入具有特定功能的电器中,通过抽象类和接口的合理设计,实现了对各类动物和电器行为的规范与扩展。
抽象类在该实验中扮演着 “模板” 的角色。以Animal抽象类为例,它定义了动物的一些共性属性和行为,如name属性表示动物名称,以及抽象方法makeSound。这个抽象方法强制要求所有继承自Animal的子类,像tiger类、lion类等,必须实现该方法,规定了每种动物都要有自己独特的发声方式。在具体实现中,tiger类重写makeSound方法输出 “嗷嗷”,lion类则输出 “咆哮” 。抽象类中还可以包含具体实现的方法,比如Animal类中可以有move方法的具体实现,描述动物移动的通用行为。这使得抽象类既提供了统一的规范,又能为子类复用部分代码,在实验场景中,当我们需要创建不同种类的动物对象并执行相关行为时,抽象类确保了所有动物都遵循既定的行为模式,增强了代码的规范性和一致性。
接口在实验里则侧重于定义行为契约,强调的是 “能做什么”。例如定义PoweredDevice接口,包含turnOn和turnOff方法,用于规范所有电器设备的开关行为。Refrigerator类和Microwave类实现该接口,分别实现具体的开关逻辑。同时,一个类可以实现多个接口,接口的这种特性让程序的功能组合更加灵活,在将动物放入电器的操作中,电器通过实现相应接口,明确了自身具备的功能,当需要对电器功能进行扩展或修改时,只需要调整对应的接口实现类,而不会影响到其他部分的代码,极大地提高了程序的可维护性和扩展性。
然而在实验过程中,对于抽象类和接口的使用边界把握还存在不足。有时会混淆抽象类和接口的应用场景,比如将一些本应使用接口定义的简单行为,错误地放到抽象类中实现,导致代码结构不够清晰。另外,在多个接口组合使用时,接口方法的命名和功能协调上出现过混乱,使得实现类在重写方法时逻辑不够简洁明了。后续需要更深入理解抽象类和接口的本质区别,根据具体需求准确选择使用,进一步优化程序设计。
集合框架
在图形程序中,集合框架通过ArrayList
集合框架的强大功能还体现在数据查询与计算上。max()方法通过遍历集合比较各元素的getArea()返回值,快速定位面积最大的图形对象,而无需考虑对象的具体类型。这种设计使得系统在处理新增图形类型(如后续可能添加的三角形)时,无需修改集合操作逻辑,只需确保新类继承自AbstractShape并实现相应方法。在计算所有图形面积之和时,集合的迭代器机制与多态调用相结合,使getSumArea()方法能够简洁地遍历所有元素并累加面积值,充分体现了集合框架在数据处理上的高效性与通用性。
然而在实践中,集合框架的应用也暴露出一些挑战。例如,在处理继承层次较深的对象(如立方体继承自矩形)时,需要特别注意属性访问的合理性,避免出现逻辑混淆。另外,集合的排序操作依赖于compareTo()方法的正确实现,若在子类中重写该方法时逻辑有误,可能导致排序结果不符合预期。后续需进一步深入理解集合框架的各种接口和实现类的特性,根据具体场景选择最优的数据结构和算法,以提升系统性能和稳定性。
JavaFx
在实验5动物装入电器实验中,JavaFX 通过可视化界面显著提升了交互体验。程序创建了包含动物选择下拉框、电器选择下拉框、装入按钮和结果显示区域的界面。当用户选择动物和电器并点击装入按钮时,JavaFX 的事件处理机制捕获该动作,调用相应的业务逻辑,将动物对象装入电器对象,并在结果区域显示操作反馈。这种实现利用了 JavaFX 的控件与数据绑定特性,下拉框选项与后台数据模型动态关联,若后续新增动物或电器类型,只需更新数据源即可自动同步到界面。
JavaFX 的场景图架构使界面元素组织清晰,通过 VBox 和 HBox 布局管理器实现了合理的空间分配与元素排列。同时,其事件驱动模型确保了界面的响应性,在处理装入操作等耗时逻辑时,界面不会阻塞,仍能响应用户的其他操作(如重置按钮)。然而在实践中,也遇到了界面布局在不同屏幕分辨率下显示不一致的问题,后续需要进一步学习 JavaFX 的响应式布局技术,以及如何优化复杂界面的渲染性能,以确保在处理更多动物和电器类型时,系统仍能保持流畅的用户体验。
踩坑心得
1. 继承与组合的误用
在实现魔方问题时,我曾错误地让SquareCube直接继承Cube类,导致代码耦合度过高。后来发现,通过组合关系(在SquareCube中包含Cube对象)能更好地复用功能,同时保持类的独立性。这让我明白:继承应谨慎使用,优先考虑组合。
2. 抽象类与接口的边界模糊
在动物装入电器实验中,我曾将PoweredDevice设计为抽象类而非接口,限制了电器类的扩展性。实际上,接口更适合定义行为契约(如turnOn()),而抽象类应侧重于提供公共实现。这个教训让我掌握了:接口定义能做什么,抽象类定义是什么。
3. 多态实现的细节陷阱
在点线面问题中,我重写display()方法时未注意返回值类型,导致编译错误。后来发现,子类方法的签名必须与父类完全一致。另外,通过基类引用调用子类特有方法时会引发ClassCastException,这让我意识到:多态调用仅限于基类定义的方法。
4. 集合框架的类型陷阱
在图形程序中,我曾忘记指定泛型类型,导致集合中混入不同类型对象,引发运行时异常。使用Collections.sort()时,若未正确实现Comparable接口,会导致ClassCastException。这些经验教会我:始终使用泛型确保类型安全,实现比较接口时注意逻辑一致性。
5. JavaFX 的线程与布局挑战
在动物装入电器的 JavaFX 实现中,我直接在事件处理线程中执行耗时操作,导致界面卡顿。后来通过Platform.runLater()解决了这个问题。另外,绝对布局导致界面在不同屏幕分辨率下显示异常,这让我认识到:JavaFX 界面更新必须在 JavaFX 应用线程中进行,优先使用布局管理器实现响应式设计。
这些踩坑经历让我明白,面向对象编程不仅要理解概念,更要在实践中注意细节。通过不断调试和反思,我逐渐掌握了类设计的平衡艺术,代码的可维护性和扩展性也得到了显著提升。
改进建议及总结
面向对象程序设计课程通过理论讲解与实践操作结合,系统梳理了封装、继承、多态等核心概念。通过 PTA 作业、实验项目和综合案例(如点线面重构、魔方系统),我逐步掌握了类设计的单一职责原则、接口与抽象类的应用边界,以及集合框架与 JavaFX 的实践技巧。课程最显著的价值在于培养了 "抽象建模" 思维 —— 从现实问题中提取对象特征,通过类层次结构实现逻辑映射,例如在动物装入电器实验中,通过接口定义行为契约,抽象类规范类型共性,使代码兼具扩展性与可维护性。这门课程的价值不仅在于技术点的掌握,更重要的是建立了 "问题抽象 - 模型设计 - 代码实现" 的完整思维链。未来在软件开发中,我将更注重接口隔离原则的应用,通过组合优于继承的设计理念避免类层次膨胀,同时借助单元测试框架验证多态行为的正确性,将课程所学转化为实际开发能力。
至于改进建议,我觉得线下课程上的很好,形式多样,内容简洁又吸引人,没有什么建议,作业与实验适中,形式多样,也没有什么建议。
浙公网安备 33010602011771号