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

15.4 个人信息

📄 一句话概括

给 15.2 登录的 admin 账号"上户口"——User 个人信息类。五个字段(登录名/密码/真实姓名/电话/邮箱)+ 官方通道 + show(),和 15.3 的 Customer 是完全同款的封装模板,换个字段名再套一遍。本节真正的考点只有一个:第一次不抄示例、照模板自己造一个类——外加"查看/修改个人信息"这条小流程,把 6.2 的 equals 又拉出来站了一班岗。


一、User 是谁:15.2 那个 admin 的实体化

15.2 写登录时,用户名密码是两个散变量 "admin"、"123456"——能跑,但糙:真想"查看/修改个人信息",散变量一转身就分家。

现在照 15.3 的模子把这个人装进对象里:登录名、密码、真实姓名、电话、邮箱五样长在同一个 User 身上。登录成功 = 门卫验明的就是这个 User 对象;后续"改密码""改电话"都对着它操作。

CRM 的三层蓝图里,User 和 Customer 是平级同事:都是"实体管数据"层,谁也不管业务,只把自己那份信息看好。

二、核心:照模板造第二个实体类

public class User {
    private String username;   // 登录名
    private String password;   // 密码
    private String realName;   // 真实姓名
    private String phone;      // 电话
    private String email;      // 邮箱

    // 全参构造
    public User(String username, String password, String realName,
                String phone, String email) {
        this.username = username;
        this.password = password;
        this.realName = realName;
        this.phone = phone;
        this.email = email;
    }

    // 无参构造(写了全参必补,15.3 的铁律不变)
    public User() {
    }

    // 五对 getXxx() / setXxx() —— 官方通道,一式五份
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    // password / realName / phone / email 同款……

    // 自我介绍
    public String show() {
        return realName + "(" + username + ")\t" + phone + "\t" + email;
    }
}

对照 15.3 的 Customer,结构一模一样:private 字段 → 全参构造 → 无参构造 → getter/setter → show()。变的只有字段名。这就是"模板"的意义:结构是抄的,业务是零——实体类永远长这样。

三、查看与修改:老朋友会师

登录成功后,"个人信息"功能就两件事:

查看——show() 一行打出来(15.3 铺的路直接用)。

修改——以"改密码"为例,这是本节最有含金量的一段:

public class Demo34 {
    public static void main(String[] args) {
        User me = new User("admin", "123456", "波仔",
                           "13800000000", "[email protected]");

        // 查看个人信息
        System.out.println("当前个人信息:" + me.show());

        // 改密码:先验旧密码,再放行 set
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入旧密码:");
        String oldPwd = sc.next();
        if ("123456".equals(oldPwd)) {          // 6.2 equals + 15.2 常量打头
            System.out.print("请输入新密码:");
            me.setPassword(sc.next());           // 15.3 单个 set 官方通道
            System.out.println("密码修改成功!");
        } else {
            System.out.println("旧密码错误,拒绝修改。");
        }
        System.out.println("修改后:" + me.show());
    }
}

一行不新学:equals 比较内容 + 常量打头防 null(6.2/15.2),单个 set 只动一个字段(15.3)。串起来就是"修改个人信息"的完整业务——分层的好处这时才尝到味道:User 什么都不用改,业务在 View 层组装。

🧪 实验 1:故意输错旧密码

把旧密码输错——看到"旧密码错误,拒绝修改",show() 打出来密码还是旧的。封装挡住了野路子:没有 setter 校验这个卡口的话,me.password = "hacked" 就直接进去了。

🧪 实验 2:给 setPassword 加安检

把新密码长度校验写进 setter:if (pwd.length() < 6) throw new IllegalArgumentException("密码至少 6 位");——这就是 5.3 说的"setter 安检升级",一处加锁全局生效,Customer 和 User 同时受益。

🧪 实验 3:查看时把密码藏起来

改 show() 让它打印 密码:****** 而不是真实密码——体会"getter 可以有选择地给",官方通道不但管写,还管给多给少。

四、五个常见误区

⚠️ 误区 1:抄 Customer 时忘改字段名

复制粘贴后 getter/setter 里还是 name/age——编译器不会提醒你"业务上不对",只会在调用处报错。抄完先通读一遍,字段名、注释全换成自己的。

⚠️ 误区 2:把业务写进 User

比如在 User 里写"登录校验"方法——User 只管装数据,登录校验是 15.2 Login 的活。实体类一沾业务,分层就散架了。

⚠️ 误区 3:改密码不验旧密码

直接 setPassword(新密码) 跑通就算完——真实系统谁能来 set 你的密码?校验旧密码这一步就是"官方通道的安检",跳过它等于封装白学。

⚠️ 误区 4:show() 打印明文密码

调试时图方便把 password 也打出来——习惯一旦养成,代码一旦流出就是事故。自我介绍可以,敏感字段打码。

⚠️ 误区 5:User 和 Customer 混成一个大类

"反正都是人,写一个 Person 类都装了吧"——看起来省事,实际字段语义混在一起(客户的性别年龄 vs 登录者的密码)。一个实体管一摊数据,15.1 的分工口诀管到类设计。

五、自测题

❓ Q1:User 类的五个字段是什么?和 Customer 有什么结构区别?

username/password/realName/phone/email。结构零区别——private 字段 + 两种构造 + getter/setter + show(),模板完全同款,只有字段名不同。

❓ Q2:改密码前为什么要先 equals 校验旧密码?

官方通道的安检:确认操作者是本人,防止任何拿到对象引用的人随意改密码。同时复习 6.2——必须 equals 不能 ==,且常量/确定非空一方打头。

❓ Q3:为什么校验、修改这些逻辑不写进 User 类?

实体类只管数据不管业务(15.1 分工口诀);写进 User 会让分层散架,User 变成什么都干的"大杂烩"。

❓ Q4:实验 2 的 setter 安检体现什么好处?

校验写在 setter 里,所有赋值入口统一把守,一处加锁全局生效——封装"保护数据"的真正含义。

❓ Q5:(毕业题)给 User 加"修改电话"功能,说出最小改动和必须的校验。

拿到 User 对象后 me.setPhone(sc.next()) 一行即成(15.3 单个 set 套路);校验上可用正则 6.8 的 1[3-9]\\d{9} 判断手机号格式,格式不对就不调用 set——安检放在通道口。

六、下一步学什么


相关笔记