2 changed files with 309 additions and 0 deletions
@ -0,0 +1,236 @@ |
|||
# 图形面积计算器重构 - 实验报告 |
|||
|
|||
## 一、实验概述 |
|||
|
|||
### 实验目的 |
|||
通过重构图形面积计算器,理解面向对象编程中的抽象类、继承和多态概念,比较组合与继承的优缺点。 |
|||
|
|||
### 实验背景 |
|||
原有 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() 方法 |
|||
|
|||
```java |
|||
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 关键字实现 |
|||
|
|||
**本项目使用继承的原因**: |
|||
```java |
|||
// 继承关系:圆 是一种 图形 |
|||
Circle extends Shape |
|||
|
|||
// 继承关系:矩形 是一种 图形 |
|||
Rectangle extends Shape |
|||
|
|||
// 继承关系:三角形 是一种 图形 |
|||
Triangle extends Shape |
|||
``` |
|||
|
|||
**继承的优点**: |
|||
✅ 代码复用:子类自动拥有父类的属性和方法 |
|||
✅ 多态性:可以用父类类型统一处理子类 |
|||
✅ 符合自然逻辑:圆确实是一种图形 |
|||
|
|||
**继承的缺点**: |
|||
❌ 耦合度高:父类改变会影响所有子类 |
|||
❌ 破坏封装:子类可以访问父类的 protected 成员 |
|||
❌ 不灵活:继承关系在编译时确定,运行时无法改变 |
|||
|
|||
--- |
|||
|
|||
### 2. 组合(Composition) |
|||
|
|||
**是什么**: |
|||
- 类与类之间的 has-a 关系 |
|||
- 一个类包含另一个类的对象作为成员 |
|||
- 用成员变量实现 |
|||
|
|||
**组合的例子**: |
|||
```java |
|||
// 组合关系:汽车 有一个 引擎 |
|||
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 属性 |
|||
- 继承避免重复代码 |
|||
|
|||
**如果用组合会怎样?** |
|||
```java |
|||
// 不推荐的组合方式 |
|||
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日 |
|||
@ -0,0 +1,73 @@ |
|||
# 图形面积计算器 - 类图 |
|||
|
|||
## UML类图(文字描述) |
|||
|
|||
``` |
|||
┌─────────────────────────┐ |
|||
│ <<abstract>> │ |
|||
│ Shape │ |
|||
├───────────────────────┤ |
|||
│ - name: String │ |
|||
├───────────────────────┤ |
|||
│ + Shape(name: String)│ |
|||
│ + getName(): String │ |
|||
│ + getArea(): double │ |
|||
│ <<abstract>> │ |
|||
└───────────┬───────────┘ |
|||
│ |
|||
┌──────────────────────┼──────────────────────┐ |
|||
│ │ │ |
|||
▼ ▼ ▼ |
|||
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐ |
|||
│ Circle │ │ Rectangle │ │ Triangle │ |
|||
├───────────────────┤ ├───────────────────┤ ├───────────────────┤ |
|||
│ - radius: double │ │ - width: double │ │ - base: double │ |
|||
│ │ │ - height: double │ │ - height: double │ |
|||
├───────────────────┤ ├───────────────────┤ ├───────────────────┤ |
|||
│ + Circle(radius) │ │ + Rectangle(w,h) │ │ + Triangle(b,h)│ |
|||
│ + getRadius() │ │ + getWidth() │ │ + getBase() │ |
|||
│ + setRadius() │ │ + setWidth() │ │ + setBase() │ |
|||
│ + getArea() │ │ + getHeight() │ │ + getHeight() │ |
|||
│ @Override │ │ + setHeight() │ │ + setHeight() │ |
|||
└───────────────────┘ │ + getArea() │ │ + getArea() │ |
|||
│ @Override │ │ @Override │ |
|||
└───────────────────┘ └───────────────────┘ |
|||
|
|||
┌─────────────────────────────────┐ |
|||
│ ShapeUtil │ |
|||
├─────────────────────────────────┤ |
|||
│ + printArea(Shape shape) │ |
|||
└─────────────────────────────────┘ |
|||
``` |
|||
|
|||
## 类图说明 |
|||
|
|||
### 类关系说明 |
|||
|
|||
1. **Shape(抽象类) |
|||
- 是所有图形的父类 |
|||
- 包含抽象方法 getArea() |
|||
- 所有子类必须实现此方法 |
|||
|
|||
2. **Circle(圆) |
|||
- 继承自 Shape |
|||
- 实现圆形面积计算:π × r² |
|||
|
|||
3. **Rectangle(矩形) |
|||
- 继承自 Shape |
|||
- 实现矩形面积计算:宽 × 高 |
|||
|
|||
4. **Triangle(三角形) |
|||
- 继承自 Shape |
|||
- 实现三角形面积计算:0.5 × 底 × 高 |
|||
|
|||
5. **ShapeUtil(工具类) |
|||
- 提供静态方法 printArea() |
|||
- 参数为 Shape 类型(多态) |
|||
- 可以接受任何 Shape 的子类 |
|||
|
|||
### 继承关系符号 |
|||
- 箭头表示继承关系(is-a) |
|||
- Circle is-a Shape |
|||
- Rectangle is-a Shape |
|||
- Triangle is-a Shape |
|||
Loading…
Reference in new issue