☕ 第十五章 综合项目:客户关系管理系统

15.1 项目开发准备

📄 一句话概括

全书第一个综合项目:客户关系管理系统(CRM)——销售员的"客户小本本",能添加、修改、删除、列出客户。本节不动大刀,只干三件事:需求分析(做什么)、类设计(拆成几个类各管什么)、搭骨架(建类占位跑通)。前面十四章的功夫,从这一节开始拧成一股绳。


一、先想清楚再动手:开发四步

新手最大的坑是上来就敲代码——敲到一半发现字段漏了、类拆错了,推倒重来。正规姿势四步走:

  1. 需求分析——这个软件要能干什么?(功能清单)
  2. 设计——拆成几个类?每个类管什么?(类蓝图)
  3. 编码——按蓝图一个个实现;
  4. 测试——边写边跑,验一个功能收一个。

本项目体量不大,但流程一步不省——麻雀虽小五脏俱全,工作里的项目就是这个流程放大一百倍。

二、需求分析:销售员的小本本

CRM = Customer Relationship Management,客户关系管理。说白了就是销售员的小本本:见了什么客户、电话多少、备注啥,记下来能随时翻、随时改。

功能清单(主菜单五项):

菜单 功能 底下要用到
1 添加客户 Scanner 输入 + 数组插入
2 修改客户 按索引查找 + 替换
3 删除客户 数组搬移补空位
4 客户列表 遍历打印
5 退出 break 跳出循环

菜单用 while(true) + switch 实现——2.4 选择、2.5 循环的老手艺,第一次正式干大活。

三、类设计:三张图纸 + 一件工具

一个类全包?能跑,但天下大乱。按"各管一摊"拆成三层:

类 角色 职责 用到
CustomerView 视图层 = 脸 主菜单循环、接收用户输入、打印表格;只管喊话,不存数据 2.4/2.5 + 14 章分层思想
CustomerList 管理层 = 库房 Customer[] 数组 + total 计数,提供 add/replace/delete/getAll/getCustomer 五个方法 2.7 数组 + 3.3 封装
Customer 实体层 = 货物 姓名/性别/年龄/电话/邮箱五个字段,private + getter/setter 3.1~3.4 面向对象全家
CMUtility 工具类 = 打字员 封装 Scanner:读菜单项、读整数、读字符串、确认 Y/N 6.3 System/6.1 包装类解析套路

分工口诀:脸管喊话,库管货,实体管数据,工具管打字。

💡 数据流向一句话

用户在 View 里打字 → CMUtility 帮忙读进来 → View 拼好一个 Customer 对象 → 交给 CustomerList 存进数组 → 列表功能再从 List 把数组拿出来遍历打印。数据只在三层之间走官方通道(方法调用),谁也不许越级摸别人口袋——这就是封装思想的项目级落地。

💡 CMUtility 直接抄

工具类教材/课程一般直接给源码(四个静态方法:readMenuSelection、readInt、readString、readConfirmSelection),照抄进项目即可——它的价值不是"学新知识",而是体会为什么 Scanner 要封装成静态方法:全项目共用一个 Scanner,代码不重复(6.3 工具类套路的实战版)。

四、动手:Demo31 项目骨架(先跑通再说)

新建项目 CRM,在 src 下建四个类(空壳占位):

// Customer.java —— 实体类,15.2 填肉
public class Customer {
}

// CustomerList.java —— 管理类,15.3 填肉
public class CustomerList {
}

// CMUtility.java —— 工具类,抄教材源码
public class CMUtility {
}

// CustomerView.java —— 视图类,主入口
public class CustomerView {
    public static void main(String[] args) {
        System.out.println("客户关系管理系统 · 项目初始化成功");
    }
}

四个文件全建好、CustomerView 跑起来能打印这句话——骨架立住了,本节的目标就完成了。看着空,意义不小:项目最怕的不是写得慢,是地基歪了。

🧪 实验 1:验证"一类一文件"

试着在一个 .java 文件里写两个 public 类——编译器直接不让:public 类名必须和文件名一致(1.3 的老规矩第一次在实战里咬人)。

🧪 实验 2:故意把 CustomerList 写成 CustermerList

拼错的类名在哪都被红线圈出——View 里引用时立刻暴露。类名错了,编译器比你还着急,这也是分层的好处:错误被挡在编译期。

🧪 实验 3:给 CustomerView 添加注释骨架

在类里把"主菜单循环""添加客户""修改客户……"先用注释占位(// TODO:添加客户)——先写目录后写书,下一节往注释里填代码。

五、五个常见误区

⚠️ 误区 1:不做需求分析直接开敲

写到添加客户才发现"邮箱要不要?年龄是 int 还是 String?"——返工。先把功能清单和字段定死再动手。

⚠️ 误区 2:Customer 字段用 public 图省事

三章的封装白学了?照旧 private + getter/setter——项目里偷的懒,就是将来 bug 常住的家。

⚠️ 误区 3:View 里直接 new 数组存客户

越级违规。数据归 CustomerList 管,View 只能调它的方法——数据只走官方通道,否则分层白分。

⚠️ 误区 4:到处 new Scanner(System.in)

每个方法各造一个 Scanner,迟早出幺蛾子。封装进 CMUtility 静态方法,全项目共用一个。

⚠️ 误区 5:把所有逻辑堆进 main

main 只负责启动(new CustomerView 让菜单转起来),增删改查各归各的方法——一个方法干一件事(2.6 的规矩在大项目里是保命符)。

六、自测题

❓ Q1:开发四步是什么?为什么不能跳过前两步?

需求分析→设计→编码→测试。跳过前两步=没想清楚就动手,字段类设计一错就大面积返工。

❓ Q2:四个类各自的职责是什么?

CustomerView 脸(菜单+交互)、CustomerList 库房(数组+增删改查)、Customer 货物(五个字段)、CMUtility 打字员(Scanner 封装)。

❓ Q3:为什么数据不许在 View 里直接存?

分层的意义:数据归 CustomerList 管理才能保证增删改查口径统一;View 越级存数据,等于绕过库房,将来换界面(如 GUI 版)全部重写。

❓ Q4:CMUtility 为什么要封装成静态方法?

Scanner 全项目共用一个,避免重复创建;静态方法不用 new 对象直接类名调用(6.3 工具类套路)。

❓ Q5:(毕业题)不写代码,画出本项目的"功能清单 + 类蓝图":主菜单五项、四个类各自的职责和它们之间的调用方向。

参考:View →(调用)→ List →(存放)→ Customer;CMUtility →(喂输入)→ View。口诀:脸管喊话,库管货,实体管数据,工具管打字。画得出这张图,15.2 起的每一节就是在图上"填肉"。

七、下一步学什么


相关笔记