“吃货联盟订餐系统”分析及改进

(1)来源
本次分析的项目为“吃货联盟订餐系统”,源来源于博客园,博客地址为: https://www.cnblogs.com/benben2013A/p/7084538.html。

(2)运行环境+运行结果
运行环境:
1.JDK版本:Java 8
2.操作系统:Windows 11
3.开发工具:IDEA
运行结果:

(3)主要问题和改善
3.1. 代码结构与设计:所有逻辑全部堆砌在 main 方法中,可读性差,不利于维护和扩展。
改善

  1. 创建 Order(订单)类,封装订单属性(订餐人、菜品、金额、状态等)。
  2. 创建 Dish(菜品)类,封装菜品属性(名称、单价、点赞数)。
  3. 创建 OrderManager(订单管理)类,负责处理订餐、签收、删除等核心业务逻辑。
  4. main 方法所在类仅负责用户界面交互和流程控制。

3.2.数据存储:使用多个固定大小的数组并行存储订单信息,数组长度固定为4,导致系统容量有限且容易出错(如数组下标管理混乱)。添加、删除订单时需要手动维护多个数组,非常繁琐且易遗漏。
改善
使用 ArrayList 来动态管理订单列表,无需担心容量上限,且添加、删除操作由集合本身保证,代码更简洁安全。

3.3功能逻辑缺陷
1.送餐费计算:订餐成功后的总计金额包含了餐费和送餐费,但送餐费的计算逻辑只在订餐时显示,并未存入 sumPrices 数组。
2. 订单状态:states 数组默认值为0,但初始化了两个订单后,第二个订单 states[1] 未显式赋值,其状态为0(已预定),这可能不符合预期
3. 点赞功能:点赞后没有即时反馈当前菜品的总赞数,用户体验稍差。
改善:

  1. 修正订餐逻辑,将计算后的 sumPrice + deliCharge 存入 sumPrices 数组。
  2. 在添加新订单时,明确设置其状态为“已预定”。
  3. 点赞成功后,重新显示当前菜品的点赞总数。

3.4代码细节问题:

  1. 拼写错误:变量名 priaiseNum 拼写错误,应为 praiseNum;注释中存在错别字,如“序叼”、“胡订单序号”。
  2. 格式混乱:“查看餐袋”功能中,输出格式使用 \t 对齐,当内容长度不一时,界面会非常混乱,难以阅读。
    改善
  3. 修正所有拼写错误和不规范的命名。
  4. 优化“查看餐袋”的输出格式,使用 String.format 或 System.out.printf 进行格式化输出,确保表格对齐美观。

(4)新代码
4.1Order类:
imageimage
4.2Dish类:
image
4.3OrderManager类:
imageimage
4.4主程序框架及改进点:
public class OrderingApp {
private static OrderManager manager = new OrderManager();
private static Scanner scanner = new Scanner(System.in);

public static void main(String[] args) {
    // ... 初始化一些菜品和订单数据 ...
    int num;
    do {
        // 显示菜单...
        int choose = getIntInput("请选择:"); // 封装了异常处理的输入方法
        switch (choose) {
            case 1:
                placeOrder(); // 将订餐逻辑抽离成单独方法
                break;
            case 2:
                viewOrders(); // 查看餐袋
                break;
            // ... 其他case ...
            case 6:
                System.out.println("感谢使用,再见!");
                return;
            default:
                System.out.println("无效选择,请重新输入。");
        }
        num = getIntInput("输入0返回主菜单,其他数字退出系统:");
    } while (num == 0);
}

// 改进点:封装了输入验证的整数读取方法
private static int getIntInput(String prompt) {
    int input = -1;
    while (true) {
        System.out.print(prompt);
        try {
            input = scanner.nextInt();
            break;
        } catch (InputMismatchException e) {
            System.out.println("输入错误,请输入一个整数。");
            scanner.next(); // 清除错误输入
        }
    }
    return input;
}

// 改进点:订餐逻辑,使用Order类和ArrayList
private static void placeOrder() {
    System.out.println("***我要订餐***");
    // 1. 获取用户输入(已做验证)
    String name = getStringInput("请输入订餐人姓名:");
    // ... 显示菜品、选择编号、份数等(已做边界检查)...
    int dishChoice = getIntInputInRange("请选择菜品编号:", 1, dishNames.length);
    // ... 计算金额、获取送餐时间地址等 ...
    
    // 2. 创建Order对象并交由Manager处理
    Order newOrder = new Order(name, dishInfo, time, address, total);
    if (manager.addOrder(newOrder)) {
        System.out.println("订餐成功!");
    } else {
        // 理论上ArrayList不会满,但可以保留业务限制
        System.out.println("订餐失败,系统繁忙。");
    }
}

}

(5)重构后的软件测试
image
image
image
image

(6)总结
6.1:难点:

  • 理解原有代码逻辑:原代码将所有功能混杂在 main 方法的 switch 语句中,变量众多,循环和条件嵌套较深。理清每个变量的作用和程序执行流程是分析阶段的主要难点。
  • 重构时的职责划分:如何将原本纠缠在一起的代码合理地拆分到不同的类和方法中,确保“高内聚、低耦合”,是设计阶段需要仔细思考的问题。
  • 确保重构后功能一致:在修改代码结构和修复缺陷的同时,必须保证所有原有功能都能正常工作,需要设计较全面的测试用例进行回归测试。

6.2耗时较久的环节:

  • 输入验证的完善:设计一个既能捕获异常、又能进行范围检查,且方便复用的输入工具方法花费了较多时间。
  • 界面格式化输出:为了让“查看餐袋”功能输出整洁的表格,调整 String.format 的格式符和对齐方式比预想的要繁琐一些。

6.3对逆向软件工程的一些思考:

  • 逆向工程不仅是读代码,更是理解设计意图:即使是这样一个简单的项目,也能从代码的写法(如用并行数组)看出作者当时对数据管理的朴素理解。逆向的过程,就是与原作者“对话”,理解其解决问题的原始思路。
  • “烂代码”是最好的教材:分析一个有缺陷的项目,比直接阅读一个完美项目收获更大。它能让你直观地感受到坏味道(如过长方法、重复代码)带来的维护成本,从而更深刻地理解设计原则和模式的价值。
  • 重构是循序渐进的过程:不必试图一次性解决所有问题。可以从最简单的代码格式化、变量重命名开始,逐步深入到结构重组和逻辑优化。每一步改进都让代码变得更好,这个过程本身就很有意义。
  • 测试是重构的安全网:在没有自动化测试的情况下进行手动重构是有风险的。这让我意识到,为现有代码编写测试(即使是手动的测试用例列表)是多么重要,它能让你有信心去修改代码而不怕破坏既有功能。
posted @ 2026-03-11 00:48  ysz11  阅读(0)  评论(0)    收藏  举报