javascript - 使用 ES6 类继承进行参数化验证的值

标签 javascript validation oop inheritance ecmascript-6

我正在重写一些旧的 Chrome 扩展代码,同时尝试学习新的 ES6 技巧,并且遇到了一些设计问题。

我的目标是提供一个值存储(由异步chrome.storage支持以实现持久性,但这超出了问题的范围)。我想要的是将一些验证与值相关联。因此,我的 StorageValues 的集合,每个值都与一个验证函数相关联。

在我的旧版本中,当我实例化一个值时,我只会传递一个验证函数,如下所示(简化):

Storage["key1"] = new Value({
  validator: ValidatorIsInteger, defaultValue: 0, /* ... */
});
Storage["key2"] = new Value({
  validator: ValidatorEnum(["a", "b", "c"]), defaultValue: "a", /* ... */
});

但是,我尝试将 Value 重写为可以使用特定验证器扩展的 class,这在当时似乎是一个好主意。再次简化:

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"};
    }
  }
}

到目前为止一切顺利。然而,我遇到了problems当尝试创建参数化子类时:

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) 之前“设置”参数化验证器。我看到了几种解决这个问题的方法,但所有这些方法似乎都缺乏:

  • 辞职,不要使用基于 class 扩展的方法 - 我想看看是否可以先修复它
  • 始终相信默认值作为调用 .set(defaultValue) 的解决方法 - 不好,因为我不希望数据意外不一致
  • 使 .set() 异步,让构造函数有机会在执行验证之前完成 - 虽然持久化后端是异步的,但存储的目的其中之一就是提供同步“缓存”

我是否没有看到这种方法的一些明显的修复方法?如果不是,而且这根本就是一个错误的工作工具,我应该如何重新组织它?

最佳答案

这是从构造函数调用可重写方法(validate,通过set)的经典问题; discussed here (不同的语言,相同的问题)。

您的具体示例提供了几种解决方法,但一般问题仍然存在。

为了解决一般问题,我直接设置 value,而不是通过 set,并使用单元测试来确保我没有创建具有以下属性的验证器:无效的默认值。毕竟,这是一个编码错误,而不是运行时错误。

但是如果您想继续调用set,有几个选项:

  • 您可能有一个没有默认值的概念,无论如何,这通常可能很有用。这可以通过让您拥有一个不期望接收默认值的 Value 构造函数来解决问题。您可以在构造后通过 setDefaultValue 或类似方法为 Value 指定默认值;该方法会验证,但这没关系,因为它将在子类中被称为构造后。

  • 您可以给 Value 一个“验证”和“非验证”状态,并让构造函数接受一个标志,表示它应该开始的状态。子类将使用 false 如果他们有特殊的验证行为,请确保所有鸭子都排成一行,然后设置验证状态(将进行验证)。

关于javascript - 使用 ES6 类继承进行参数化验证的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37776479/

相关文章:

javascript - 使用 Ajax 获取数据后触发 jQuery 重新绘制

javascript - 如何使用 AJAX 传递 2 个值以与 PHP 进行比较

python - 初学者 : python namespace collision?

c# - 迭代器中的副作用被认为是有害的?

.net - 性能是拥有单例或静态类的充分理由吗?

asp.net - javascript windows "Yes/No"询问两次?

Javascript 更改 innerHTML 函数不起作用

javascript - 如何修改Highcharts中的负轴条形图?

validation - knockout 验证 isValid() 不起作用

正则表达式模式的 JavaScript 验证