You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 10:35:54