Javascript ES6类固有参数化验证值
我正在重写一些旧的Chrome扩展代码,同时尝试学习新的ES6技巧,我遇到了一些设计问题 我的目标是提供一个值存储(由异步Javascript ES6类固有参数化验证值,javascript,validation,oop,inheritance,ecmascript-6,Javascript,Validation,Oop,Inheritance,Ecmascript 6,我正在重写一些旧的Chrome扩展代码,同时尝试学习新的ES6技巧,我遇到了一些设计问题 我的目标是提供一个值存储(由异步chrome.storage支持持久性,但这超出了问题的范围)。我想要的是将一些验证与值关联起来。因此,我的存储是值的集合,每个值都与验证函数关联 在我的旧版本中,当我实例化一个值时,我只会传递一个验证函数,类似这样(简化): 然而,我正试图用值作为一个类重写它,这个类可以通过特定的验证器进行扩展,这在当时似乎是个好主意。同样,简化: Storage["key1"] = ne
chrome.storage
支持持久性,但这超出了问题的范围)。我想要的是将一些验证与值关联起来。因此,我的存储
是值
的集合,每个值都与验证函数关联
在我的旧版本中,当我实例化一个值时,我只会传递一个验证函数,类似这样(简化):
然而,我正试图用值
作为一个类
重写它,这个类可以通过特定的验证器进行扩展,这在当时似乎是个好主意。同样,简化:
Storage["key1"] = new Value({
validator: ValidatorIsInteger, defaultValue: 0, /* ... */
});
Storage["key2"] = new Value({
validator: ValidatorEnum(["a", "b", "c"]), defaultValue: "a", /* ... */
});
class Value {
constructor(key, defaultValue) {
this.key = key;
this.defaultValue = defaultValue;
this.set(defaultValue);
}
set(newValue) {
var validationResult = this.validate(newValue);
if (validationResult.pass) {
this.value = newValue;
return newValue;
} else {
throw new RangeError(
`Value ${newValue} for ${this.key} failed validation: ${validationResult.message}`
);
}
}
get() { return this.value; }
// Overload in children
validate(value) {
return {pass: true};
}
}
class IntegerValue extends Value {
validate(value) {
if (Number.isInteger(value)) {
return {pass: true};
} else {
return {pass: false, message: "Value must be an integer"};
}
}
}
到目前为止还不错。但是,我在尝试创建参数化子类时遇到:
class EnumValue extends Value {
constructor(key, defaultValue, possibleValues) {
this.possibleValues = possibleValues; // NUH-UH, can't set that before super()
super(key, defaultValue);
}
// Will be called from parent constructor
validate(value) {
if (this.possibleValues.includes(value)) {
return {pass: true};
} else {
return {pass: false, message: `Value must be in [${this.possibleValues}]`};
}
}
}
问题在于在调用.set(defaultValue)
之前“设置”参数化验证器。我认为有几种方法可以解决这个问题,但所有这些方法似乎都不具备:
- 辞职,不要使用
-基于扩展的方法-我想看看是否可以先修复它类
- 始终信任默认值作为调用
-bad的变通方法,因为我不希望意外地出现不一致的数据.set(defaultValue)
- 使
异步,使构造函数有机会在执行验证之前完成-虽然持久化后端是异步的,但.set()
存储的目的是提供同步“缓存”
我是否没有看到这种方法的一些明显的修正?如果不是,并且这对于工作来说只是一个错误的工具,我应该如何重新组织它?这是从构造函数调用可重写方法(
validate
,viaset
)的典型问题;(不同的语言,相同的问题)
您的具体示例有几个变通方法,但一般问题仍然存在
为了解决一般问题,我直接设置value
,而不是通过set
,并使用单元测试来确保我没有创建具有无效默认值的验证器。这毕竟是一个编码错误,而不是运行时错误
但如果您想继续调用set
,有几个选项:
- 您可以使用
值的概念,该值没有默认值,这在一般情况下可能很有用。这将通过让您拥有一个不希望接收默认值的
构造函数来解决问题。您可以通过值
或类似方式,在构建后为setDefaultValue
提供默认值;该方法将进行验证,但这很好,因为它将在子类中被称为后期构造值
- 您可以给
一个“正在验证”和“未验证”状态,并让构造函数接受一个标志,它应该从哪个状态开始。子类将使用Value
,如果它们有特殊的验证行为,确保它们的所有鸭子都在一行中,然后设置验证状态(将进行验证)false