封装类属性时校验逻辑的核心是将校验放在setter中,确保每次赋值都经过验证;构造函数应调用setter而非直接赋值私有字段,避免绕过校验;强约束场景抛异常,弱约束可设默认值。

封装类属性时校验逻辑的核心是:把校验放在属性的 setter 中,确保每次赋值都经过验证;同时避免在 getter 中做副作用操作,也不在构造函数里绕过校验直接赋值。
校验逻辑写在 setter 里,而非构造函数或方法中
setter 是拦截赋值的天然入口,适合集中控制数据合法性。构造函数应调用 setter(通过 this.xxx = value),而不是直接给私有字段赋值,否则会跳过校验。
- ✅ 正确:在 setter 内判断并抛出错误或设默认值
- ❌ 错误:构造函数中直接 this._age = age,绕过校验
- ❌ 错误:把校验逻辑分散到多个业务方法里,难以维护
校验要明确失败后果:抛异常 or 设默认值?
根据场景选择处理方式。强约束场景(如 ID、必填字段)建议抛 Error;弱约束或容错场景(如用户输入年龄为负数)可自动修正为默认值。
- 年龄不能为负:setter 中 if (value
- 邮箱格式宽松:可对非标准格式做 trim()、toLowerCase() 后再存,不报错
- 避免静默失败——既不报错也不修正,会让问题延迟暴露
复杂校验可抽成独立方法,但别引入外部依赖
把校验逻辑拆成私有方法(如 isValidEmail(value))更易读、可复用、方便单元测试。但该方法应纯函数化:只依赖输入参数,不读取 this 状态或调用异步操作。
- ✅ 可:检查字符串长度、正则匹配、数值范围
- ❌ 不可:调用 API 验证手机号是否已注册、读取全局配置做条件判断
- 若真需异步校验(如唯一性检查),应另设异步方法(如 async validateUsername()),不塞进 setter
注意只读属性和初始化时机
有些属性只应在创建时设一次(如订单编号),后续不可改。可用私有字段 + 无 setter 的 getter 实现;若需初始化校验,仍在 constructor 中调用校验函数,并将结果赋给私有字段。
- 只读 ID:声明 private _id: string,只提供 getter,constructor 中校验后赋值
- 避免 getter 中重复校验或计算——它可能被频繁调用,应保持轻量
- TypeScript 用户可配合 readonly 或 private set 语法强化约束










