TypeScript面向对象编程中对象状态更新的最优方案探讨
在OOP中保持对象一致性的状态更新最优方案探讨
我在应用中采用面向对象编程(OOP),正寻求在保持对象一致性的前提下更新其状态的最优方法。我已编写了实现代码,但想了解是否有更优方案,以及OOP领域是否存在成熟的设计模式可借鉴。
以下是我编写的代码:
export class AccessProfile { id!: number; active!: boolean; name!: string; createdAt!: Date; createdBy!: string | null; createdFrom!: SystemModule; updatedAt!: Date; updatedBy!: string | null; updatedFrom!: SystemModule; environment!: Environment; hierarchy!: number | null; permissions!: Set<string>; public update( { updatedFrom, updatedBy = null, name, active, hierarchy, permissions }: { updatedFrom: SystemModule, updatedBy?: string | null, name?: string, active?: boolean, hierarchy?: number | null, permissions?: Set<string>, } ) { const backup = { name: this.name, active: this.active, hierarchy: this.hierarchy, permissions: this.permissions }; try { if (name !== undefined) { name = AccessProfile.sanitizeName(name); if (this.name !== name) { AccessProfile.validateName(name); this.name = name; } } if (active !== undefined && this.active !== active) { this.active = active; } if (hierarchy !== undefined) { hierarchy = AccessProfile.sanitizeHierarchy(hierarchy); if (this.hierarchy !== hierarchy) { AccessProfile.validateHierarchy(hierarchy); this.hierarchy = hierarchy; } } if ( permissions !== undefined && !permissionsAreEqual(permissions, this.permissions) ) { this.permissions = permissions; } if (this.hierarchy !== backup.hierarchy && this.permissions !== backup.permissions) { AccessProfile.validateHierarchyAndPermissions({ hierarchy: this.hierarchy, permissions: this.permissions }); } else if (this.hierarchy !== backup.hierarchy) { AccessProfile.validateHierarchyAndPermissions({ hierarchy: this.hierarchy, permissions: backup.permissions }); } else if (this.permissions !== backup.permissions) { AccessProfile.validateHierarchyAndPermissions({ hierarchy: backup.hierarchy, permissions: this.permissions }); } this.updatedFrom = updatedFrom; this.updatedBy = updatedBy; this.updatedAt = new Date(); return this; } catch (err) { this.name = backup.name; this.active = backup.active; this.hierarchy = backup.hierarchy; this.permissions = backup.permissions; throw err; } } } // 辅助函数(假设已定义) function permissionsAreEqual(a: Set<string>, b: Set<string>): boolean { if (a.size !== b.size) return false; for (const perm of a) { if (!b.has(perm)) return false; } return true; }
现有实现的优点
- 实现了更新失败时的状态回滚,保证对象始终处于一致状态
- 包含了字段级的清洗(sanitize)和校验逻辑,避免非法值进入对象
- 处理了
hierarchy与permissions的联合校验,维护跨字段的业务规则
可优化方向与可借鉴的设计模式
1. 拆分update方法职责
当前update方法承担了字段更新、校验、回滚等多个职责,代码嵌套较深。可以将逻辑拆分:
- 把单个字段的更新逻辑抽成私有方法(如
#updateName、#updateHierarchy),每个方法只负责对应字段的清洗、校验和更新 - 将联合校验逻辑单独抽成独立方法,简化嵌套的
if-else判断
2. 采用不可变对象模式
不直接修改原对象,而是返回一个新的实例。这种模式天然保证原对象的一致性,无需手动回滚:
- 私有构造函数,通过静态方法创建实例,避免外部直接修改内部状态
update方法构建新的候选实例,完成所有校验后返回,失败时原对象不受任何影响
优化后的示例代码:
export class AccessProfile { id!: number; active!: boolean; name!: string; createdAt!: Date; createdBy!: string | null; createdFrom!: SystemModule; updatedAt!: Date; updatedBy!: string | null; updatedFrom!: SystemModule; environment!: Environment; hierarchy!: number | null; permissions!: Set<string>; private constructor(data: Partial<AccessProfile>) { Object.assign(this, data); } public static create(initialData: Omit<AccessProfile, 'updatedAt'>): AccessProfile { return new AccessProfile({ ...initialData, updatedAt: new Date() }); } public update( { updatedFrom, updatedBy = null, name, active, hierarchy, permissions }: { updatedFrom: SystemModule, updatedBy?: string | null, name?: string, active?: boolean, hierarchy?: number | null, permissions?: Set<string>, } ): AccessProfile { const updates: Partial<AccessProfile> = { updatedFrom, updatedBy, updatedAt: new Date() }; // 处理name字段 if (name !== undefined) { const sanitizedName = AccessProfile.sanitizeName(name); if (sanitizedName !== this.name) { AccessProfile.validateName(sanitizedName); updates.name = sanitizedName; } } // 处理active字段 if (active !== undefined && active !== this.active) { updates.active = active; } // 处理hierarchy字段 if (hierarchy !== undefined) { const sanitizedHierarchy = AccessProfile.sanitizeHierarchy(hierarchy); if (sanitizedHierarchy !== this.hierarchy) { AccessProfile.validateHierarchy(sanitizedHierarchy); updates.hierarchy = sanitizedHierarchy; } } // 处理permissions字段 if (permissions !== undefined && !permissionsAreEqual(permissions, this.permissions)) { updates.permissions = permissions; } // 构建候选实例 const candidate = new AccessProfile({ ...this, ...updates }); // 执行联合校验 AccessProfile.validateHierarchyAndPermissions({ hierarchy: candidate.hierarchy, permissions: candidate.permissions }); return candidate; } // 原有清洗和校验方法保持不变 private static sanitizeName(name: string): string { return name.trim(); } private static validateName(name: string): void { if (!name || name.length < 3) { throw new Error('名称长度不能少于3个字符'); } } private static sanitizeHierarchy(hierarchy: number | null): number | null { return hierarchy === null ? null : Math.max(0, hierarchy); } private static validateHierarchy(hierarchy: number | null): void { if (hierarchy !== null && hierarchy < 0) { throw new Error('层级不能为负数'); } } private static validateHierarchyAndPermissions({ hierarchy, permissions }: { hierarchy: number | null, permissions: Set<string> }): void { // 示例校验逻辑:若层级为0,必须包含admin权限 if (hierarchy === 0 && !permissions.has('admin')) { throw new Error('层级0的配置必须包含admin权限'); } } } function permissionsAreEqual(a: Set<string>, b: Set<string>): boolean { if (a.size !== b.size) return false; for (const perm of a) { if (!b.has(perm)) return false; } return true; }
3. 借鉴命令模式
适合复杂的批量更新场景,将每个更新操作封装成命令对象,包含执行、撤销逻辑:
- 每个命令负责单一更新操作(如
UpdateNameCommand、UpdateHierarchyCommand) - 维护一个命令队列,执行时依次执行命令,失败时依次撤销所有已执行的命令
- 优点是支持批量操作的撤销/重做,逻辑更清晰
总结
- 不可变对象模式是保持对象一致性的简洁方案,无需回滚逻辑,适合大多数场景
- 命令模式适合复杂的多步骤更新,支持撤销操作
- 拆分职责能提升代码的可维护性和可测试性,降低后续迭代的复杂度
内容的提问来源于stack exchange,提问作者Cristofer
相关产品推荐
相关产品推荐

