You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6.3 KiB

图形面积计算器重构 - 实验报告

一、实验概述

实验目的

通过重构图形面积计算器,理解面向对象编程中的抽象类、继承和多态概念,比较组合与继承的优缺点。

实验背景

原有 Circle、Rectangle、Triangle 类独立存在,无法统一处理。通过引入抽象类 Shape,实现代码的统一管理和复用。


二、AI使用情况记录

1. AI协助项目创建

  • 创建项目结构:通过 Trae IDE 环境快速创建项目目录
  • 文件生成:使用代码生成工具创建 6 个 Java 类文件
  • 编译运行:使用终端工具编译和测试程序

2. AI代码协助

  • 抽象类设计:协助设计 Shape 抽象类,包含抽象方法 getArea()
  • 继承关系:实现 Circle、Rectangle、Triangle 继承 Shape
  • 多态实现:设计 ShapeUtil 的 printArea() 方法
  • 类图绘制:生成 UML 类图描述

3. AI功能总结

功能 使用情况
文件创建 自动创建 7 个文件
代码生成 生成完整 Java 代码
编译运行 自动编译和测试
文档生成 生成类图和报告

三、核心设计思路

1. 抽象类 Shape 的设计

为什么使用抽象类

  • 定义统一接口:所有图形都有 getArea() 方法
  • 强制子类实现:抽象方法确保每个图形都必须计算面积
  • 代码复用:共享 name 属性和 getName() 方法
public abstract class Shape {
    private String name;
    
    public Shape(String name) {
        this.name = name;
    }
    
    public abstract double getArea();
}

2. 继承关系设计

Circle、Rectangle、Triangle 继承 Shape

  • is-a 关系:圆是一种图形,矩形是一种图形,三角形是一种图形
  • 复用代码:继承 name 属性,无需重复定义
  • 实现多态:每个图形按自己的方式计算面积

3. 多态的应用

ShapeUtil.printArea(Shape shape)

  • 参数是 Shape 类型
  • 可以接受 Circle、Rectangle、Triangle 任何子类
  • 自动调用对应子类的 getArea() 方法

四、组合 vs 继承

问题:组合 vs 继承,什么时候用哪个?

1. 继承(Inheritance)

是什么

  • 类与类之间的 is-a 关系
  • 子类继承父类的属性和方法
  • 用 extends 关键字实现

本项目使用继承的原因

// 继承关系:圆 是一种 图形
Circle extends Shape

// 继承关系:矩形 是一种 图形
Rectangle extends Shape

// 继承关系:三角形 是一种 图形
Triangle extends Shape

继承的优点 代码复用:子类自动拥有父类的属性和方法 多态性:可以用父类类型统一处理子类 符合自然逻辑:圆确实是一种图形

继承的缺点 耦合度高:父类改变会影响所有子类 破坏封装:子类可以访问父类的 protected 成员 不灵活:继承关系在编译时确定,运行时无法改变


2. 组合(Composition)

是什么

  • 类与类之间的 has-a 关系
  • 一个类包含另一个类的对象作为成员
  • 用成员变量实现

组合的例子

// 组合关系:汽车 有一个 引擎
public class Car {
    private Engine engine;  // 组合
    
    public Car() {
        this.engine = new Engine();
    }
}

public class Engine {
    // 引擎的功能
}

组合的优点 低耦合:类之间相对独立 灵活性:运行时可以替换组合的对象 符合设计原则:优先使用组合而非继承

组合的缺点 代码较多:需要显式调用组合对象的方法 不能直接复用:无法自动继承功能


3. 选择原则:什么时候用继承,什么时候用组合?

场景 推荐使用 原因
is-a 关系(是一种) 继承 圆是一种图形,符合继承逻辑
has-a 关系(有一个) 组合 汽车有一个引擎,使用组合
需要代码复用 继承 子类可以复用父类代码
需要灵活性 组合 运行时可以动态改变
需要多态 继承 父类引用指向子类对象

4. 本项目为什么选择继承?

分析

  1. is-a 关系明确

    • 圆 是一种 图形
    • 矩形 是一种 图形
    • 三角形 是一种 图形
  2. 需要多态

    • ShapeUtil.printArea(Shape shape) 需要统一处理
    • 用 Shape 类型可以接受任何图形
  3. 代码复用

    • 所有图形都有 name 属性
    • 继承避免重复代码

如果用组合会怎样?

// 不推荐的组合方式
public class Circle {
    private Shape shape;  // 组合
    
    public Circle() {
        this.shape = new Shape("圆");
    }
}

这样就失去了多态的优势,不适合本项目。


五、实验总结

1. 完成的工作

创建抽象类 Shape,包含抽象方法 getArea() 让三个图形继承 Shape,实现面积计算 编写 ShapeUtil,提供 printArea() 方法 绘制完整的 UML 类图 完成实验报告,记录 AI 使用情况 回答"组合 vs 继承"问题

2. 学到的知识点

  • 抽象类的定义和使用
  • 继承关系的实现
  • 多态的实际应用
  • 组合与继承的对比
  • 面向对象设计原则

3. 代码验证结果

程序运行成功,输出:

========== 图形面积计算器测试 ==========
--- 圆形测试 ---
图形名称: 圆
面积: 78.53981633974483
----------------------
--- 矩形测试 ---
图形名称: 矩形
面积: 24.0
----------------------
--- 三角形测试 ---
图形名称: 三角形
面积: 20.0
----------------------
========== 测试完成 ==========

六、反思

1. 继承的使用场景

通过本次实验,我深刻理解了继承的适用场景:

  • 当存在明确的 is-a 关系时
  • 当需要多态性时
  • 当需要代码复用时

2. 设计原则的重要性

"优先使用组合而非继承"是重要的设计原则,但不是绝对的。关键是根据具体场景选择合适的方式。

3. AI 工具的价值

AI 工具在代码生成、项目搭建、文档编写等方面大大提高了效率,但核心的设计思路和概念理解还需要自己掌握。


实验完成日期:2026年3月28日