我在我的应用程序中使用面向对象编程,我试图找出改变对象状态同时保持其一致性的最佳方法。我已经编写了一个代码来实现这一点,但是有更好的方法吗?有人在 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;
}
}
}
我正在尝试找出改变对象状态同时保持其一致性的最佳方法。
我想说,规范且确实最干净的方法是分两个阶段构建
update
方法:1)验证和调整参数(并抛出无效数据); 2) 将(现在有效)数据分配给实例属性。下面是一个最小的示例,代码中还有一些建议。
顺便说一句,使用单个参数/变量与对象及其属性几乎完全相同,指导原则应该是可读性:也就是说,
Object.assign
确实可以节省几行代码,但另一方面它不允许优化仅分配给更改的属性。
export interface ProfileData {
hierarchy: number | null;
permissions: Set<string>;
}
export class Profile implements ProfileData {
hierarchy: ProfileData["hierarchy"];
permissions: ProfileData["permissions"];
/**
* @throws {Error} Invalid argument
* @throws {Error} Invalid arguments
*/
constructor({
hierarchy,
permissions,
}: ProfileData) {
// We SHOULD validate data here as well, which
// hints at extracting a data validation function
// to be used here as well as in `update`...
this.hierarchy = hierarchy;
this.permissions = permissions;
}
/**
* @throws {Error} Invalid argument
* @throws {Error} Invalid arguments
*/
public update({
hierarchy,
permissions,
}: Partial<ProfileData>) {
// (1) Validate and adjust data:
// (1.1) Validate and adjust data values:
if (typeof hierarchy === "undefined") {
hierarchy = this.hierarchy;
}
else {
hierarchy = Profile.sanitizeHierarchy(hierarchy);
Profile.validateHierarchy(hierarchy);
}
if (typeof permissions === "undefined") {
permissions = this.permissions;
}
// (1.2) Cross-validate data:
Profile.validateHierarchyAndPermissions(hierarchy, permissions);
// (2) Assign (now valid) data:
// These optimizations, skipping assignments,
// usually are overkill, anyway here we go:
if (hierarchy !== this.hierarchy) {
this.hierarchy = hierarchy;
}
if (!Profile.permissionsAreEqual(permissions, this.permissions)) {
this.permissions = permissions;
}
return this;
}
static permissionsAreEqual(
permissions1: ProfileData["permissions"],
permissions2: ProfileData["permissions"],
): boolean {
throw "NOT YET IMPLEMENTED";
}
// There is a *smell* associated with a `validate` that
// takes in input the same type as in output: if there is
// a `validate`, then the type of input supposedly is not
// the same as the type of valid data... and, along those
// lines, the validation functions below should rather
// return an `asserts` type. But I didn't have enough info
// to fully close the circle here, also considering that you
// have made no such distinction in your `update` function...
static sanitizeHierarchy(
hierarchy: ProfileData["hierarchy"],
): ProfileData["hierarchy"] {
throw "NOT YET IMPLEMENTED";
}
/**
* @throws {Error} Invalid argument
*/
static validateHierarchy(
hierarchy: ProfileData["hierarchy"],
): void | never {
throw "NOT YET IMPLEMENTED";
}
/**
* @throws {Error} Invalid arguments
*/
static validateHierarchyAndPermissions(
hierarchy: ProfileData["hierarchy"],
permissions: ProfileData["permissions"],
): void | never {
throw "NOT YET IMPLEMENTED";
}
}