必须将会员等级字段设为private并仅通过含强校验的setter修改:禁止外部直赋,枚举限定合法值,防御引用篡改,getter返回不可变视图。

核心思路是:把会员等级字段设为 private,彻底切断外部直接赋值路径;所有修改必须经过你完全可控的 setter,并在其中嵌入不可绕过的业务规则校验。
1. 用 private 封死直连通道
不加 private,任何代码都能写 user.level = "VIP99" 或 user.level = -1,校验形同虚设。Java、C#、TypeScript 等语言中,private 是强制性的编译时防线——不是“建议别改”,而是“改了就报错”。
- 错误示范:
public String level;→ 外部可任意覆盖 - 正确做法:
private String level;→ 外部连点号都点不出来
2. 在 setter 中执行强约束校验
校验逻辑必须主动拒绝非法值,而不是静默修正或忽略。常见策略包括:
- 枚举限定:只允许预定义等级(如
"GUEST"、"MEMBER"、"SILVER"、"GOLD"、"PLATINUM"),其他字符串一律抛IllegalArgumentException - 数值映射防伪造:若等级底层用 int 表示,需同时校验数字范围(如 0–5)和对应名称一致性,避免传入
setLevel(99)后内部状态错乱 - 来源可信检查(进阶):可增加一个
source参数,例如setLevel("GOLD", "system-promotion"),拒绝来自"client-input"的高阶等级请求
3. 防御性处理引用类型与副作用
如果等级关联权限列表、折扣系数等对象,setter 内部不能直接引用传入参数:
- 错误:
this.permissions = permissions;→ 外部后续修改 permissions,等于间接篡改内部状态 - 正确:
this.permissions = new HashSet(permissions);或返回不可变副本:Collections.unmodifiableSet(...) - 同步更新衍生字段:设为
"PLATINUM"时,自动将maxDownloadSpeed设为 1024,避免状态不一致
4. Getter 补充读取安全
防止外部拿到后反向污染:
- 返回不可变视图:如
getLevel()返回level.toUpperCase()或枚举常量,而非原始字符串 - 隐藏敏感细节:不暴露内部编号或过期时间,只返回对外友好的描述
- 避免 getter 触发副作用:不要在 getter 里查数据库或改状态,它应是纯读取

















