软统迭代一文档

JClassDiagram 迭代一设计文档(第95组)

团队介绍

姓名 学号 QQ号 职责
卞浩宇 221098106 3255698603 撰写代码
翟志阳 221250161 3056593724 撰写文档
周屿杨 221870148 3591599547 撰写文档
顾益铭 221250142 2408985579 撰写文档

项目目标

设计并使用 Java 代码实现 JClassDiagram 工具,该工具能读取指定 Java 文件,分析处理后在控制台输出类图的 PlantUML 文本形式 。具体包括:

  • 提取类和接口信息:提取类(不含抽象类)以及接口的相关信息。
  • 分析继承和实现关系:分析类与类之间的继承关系,类与接口之间的实现关系。
  • 生成类图文本:生成整体类图的 PlantUML 语法文本。

系统设计

总体设计

系统主要分为主程序模块和测试模块,主程序模块负责核心功能实现,测试模块用于验证主程序功能的正确性。

主要模块及关系

主程序模块(main/java

  • Main.java:作为程序的入口点,负责启动整个系统。

  • diagram 包:

    • AccessModifier.java:可能用于定义类、方法和字段的访问修饰符相关逻辑。

    • ClassDiagram.java:表示类图,可能包含类、关系等信息。

    • ClassDiagramGenerator.java:负责生成类图,可能根据代码中的类信息进行转换。

    • FieldInfo.java:存储类的字段信息,如字段名、类型等。

    • MethodInfo.java:存储类的方法信息,如方法名、参数、返回值等。

    • Parameter.java:存储方法的参数信息,如参数名、类型等。

    • TypeInfo.java:存储类型信息,如类、接口等。

测试模块(test

  • test/java 包:
    • lab1 子包:包含多个测试类,用于测试主程序在不同场景下的功能,如单类测试、多类测试、关系测试等。
  • test/resources 包:
    • lab1 子包:包含多个示例 Java 类文件,用于为测试提供数据。

模块关系

  • Main.java 调用 diagram 包中的类来完成类图的生成。
  • test/java 包中的测试类会调用 main/java 中的类进行功能测试。
  • test/resources 包中的示例 Java 类文件为测试类提供测试数据。

图形描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
+-----------------+
| Main.java |
+-----------------+

+-----------------+
| diagram 包 |
| - AccessModifier|
| - ClassDiagram |
| - ClassDiagramGenerator |
| - FieldInfo |
| - MethodInfo |
| - ParameterInfo |
| - TypeInfo |
+-----------------+

+-----------------+
| test/java 包 |
| - lab1 |
+-----------------+

+-----------------+
| test/resources |
| - lab1 |
+-----------------+

类设计

系统主要类及其关系

ClassDiagramGenerator

​ ↓ (创建)

ClassDiagram

​ ↓ (包含多个)

TypeInfo

​ ↓ (包含多个)

​ ├── FieldInfo

​ ├── MethodInfo

​ │ ↓ (包含多个)

​ │ ParameterInfo

​ └── AccessModifier

迭代一类图

涉及的设计模式

访问者模式(Visitor Pattern)

ClassDiagramGenerator 作为访问者,遍历并解析 Java 源代码,不同类型的节点(类、接口、方法、字段)作为被访问者,这种设计使得添加新的解析功能变得容易。

组合模式(Composite Pattern)

TypeInfo 作为组合节点,FieldInfoMethodInfo 作为叶子节点,这种层次结构使得系统能够统一处理不同类型的元素。

策略模式(Strategy Pattern)

AccessModifiertoSymbol() 方法提供了不同的访问修饰符表示策略,可以轻松添加新的访问修饰符表示方式。

数据结构与算法设计

关键算法设计

代码解析与关系分析

系统通过 JavaParser 库实现源码解析,核心算法流程如下:

AST 解析与类型声明提取
  • 输入:Java 源文件路径 (Path 对象)。
  • 输出:构建 TypeInfo 对象集合。
  • 步骤
    • 使用 StaticJavaParser.parse() 将源码解析为 抽象语法树 (AST)
    • 遍历 AST 中的 TypeDeclaration,过滤出 ClassOrInterfaceDeclaration 节点。
    • 根据节点类型(类或接口)创建 TypeInfo 对象,记录名称、字段、方法及继承关系。
  • 代码片段
1
2
3
4
5
6
7
8
CompilationUnit cu = StaticJavaParser.parse(sourcePath.toFile());
for (TypeDeclaration<?> typeDec : cu.getTypes()) {
if (typeDec instanceof ClassOrInterfaceDeclaration) {
ClassOrInterfaceDeclaration cid = (ClassOrInterfaceDeclaration) typeDec;
TypeInfo typeInfo = new TypeInfo(cid.getNameAsString(), cid.isInterface());
// 解析继承关系、字段、方法...
}
}
继承关系分析
  • 类继承:从 extendedTypes 中提取第一个父类(仅支持单继承)。
  • 类实现接口:遍历 implementedTypes,记录所有实现的接口。
  • 接口继承接口:遍历 extendedTypes,记录所有父接口。
  • 代码片段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 类继承
if (!cid.isInterface() && !cid.getExtendedTypes().isEmpty()) {
typeInfo.superClass = cid.getExtendedTypes(0).getNameAsString();
}
// 类实现接口
for (ClassOrInterfaceType impl : cid.getImplementedTypes()) {
typeInfo.implementedInterfaces.add(impl.getNameAsString());
}
// 接口继承接口
if (cid.isInterface()) {
for (ClassOrInterfaceType ext : cid.getExtendedTypes()) {
typeInfo.extendedInterfaces.add(ext.getNameAsString());
}
}
访问修饰符处理
  • 通用规则:检查 public / protected / private,否则标记为包级 (PACKAGE)。
  • 接口方法特殊规则:强制设为 public(符合 Java 8 规范)。
  • 代码片段
1
2
3
4
5
// 接口方法强制设为 public
public AccessModifier getAccessModifierForMethod(MethodDeclaration method) {
if (method 位于接口中) return AccessModifier.PUBLIC;
else return getAccessModifier(method); // 通用逻辑
}

UML 生成算法

  • 输入TypeInfo 对象集合。
  • 输出:符合 PlantUML 规范的字符串。
  • 关键逻辑
    • 类型输出顺序:优先输出类,后输出接口。
    • 成员排序:字段与方法按访问修饰符排序(PRIVATE → PROTECTED → PACKAGE → PUBLIC)。
    • 关系生成
      1. 类继承类:父类 <|-- 子类
      2. 类实现接口:接口 <|.. 类
      3. 接口继承接口:父接口 <|-- 子接口
  • 代码片段
1
2
3
4
5
6
7
8
// 成员排序
type.fields.sort((f1, f2) -> accessComparator.compare(f1.access, f2.access));
type.methods.sort((m1, m2) -> accessComparator.compare(m1.access, m2.access));

// 关系生成, 以继承关系为例
if (!type.isInterface && type.superClass != null && !type.superClass.isEmpty()) {
sb.append(type.superClass).append(" <|-- ").append(type.name).append("\n");
}

数据结构设计

系统通过分层模型存储解析结果,核心数据结构如下:

模型类层级

类名 属性与作用
TypeInfo name: 类型名称 isInterface: 是否为接口 fields: 字段列表 methods: 方法列表 superClass: 父类(类有效) implementedInterfaces: 实现的接口(类有效)extendedInterfaces: 继承的接口(接口有效)
FieldInfo name: 字段名 type: 字段类型 isStatic: 是否静态 access: 访问修饰符
MethodInfo name: 方法名 returnType: 返回类型 isStatic: 是否静态 access: 访问修饰符 parameters: 参数列表(ParameterInfo 对象集合)
ParameterInfo name: 参数名 type: 参数类型

数据存储示例

TypeInfo 为例,存储类的完整信息:

1
2
3
4
5
TypeInfo userService = new TypeInfo("UserService", false);
userService.superClass = "BaseService";
userService.implementedInterfaces.add("AuthService");
userService.fields.add(new FieldInfo("logger", "Logger", true, AccessModifier.PRIVATE));
userService.methods.add(new MethodInfo("getUser", "User", false, AccessModifier.PUBLIC));

数据结构扩展性

  • 支持泛型:可在 FieldInfoMethodInfo 中添加 genericTypes 属性。
  • 支持注解:在 TypeInfoFieldInfoMethodInfo 中增加 annotations 列表。

算法与数据结构总结

  • 精准解析:通过 AST 遍历提取代码结构,处理 Java 语法细节(如接口方法默认修饰符)。
  • 高效存储:分层模型 (TypeInfo 等) 解耦数据与逻辑,支持快速访问和扩展。
  • 灵活生成:按 PlantUML 规范生成代码,通过排序和分类保证输出可读性。

附录

实际工作安排

卞浩宇:Java 代码撰写,git 群组创建。

翟志阳:文档撰写,类设计部分与绘图。

周屿杨:文档撰写,数据结构与算法设计部分与运行结果。

顾益铭:文档撰写,总体设计部分与格式汇总。

运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@startuml
class BinarySearchTree {
- root: BinaryNode
- contains(x: Integer, t: BinaryNode): boolean
- findMin(t: BinaryNode): BinaryNode
- findMax(t: BinaryNode): BinaryNode
- insert(x: Integer, t: BinaryNode): BinaryNode
- remove(x: Integer, t: BinaryNode): BinaryNode
- printTree(t: BinaryNode): void
+ makeEmpty(): void
+ isEmpty(): boolean
+ contains(x: Integer): boolean
+ findMin(): Integer
+ findMax(): Integer
+ insert(x: Integer): void
+ remove(x: Integer): void
+ printTree(): void
}
@enduml

运行结果展示


软统迭代一文档
https://lngym.top/课程作业/软统迭代一文档/
作者
lngym
发布于
2025年3月31日
许可协议