JavaScriptでclassの使い方。「数値型のValue Objet」

コンピュータ

Value Objectは値に意味をもたせることが目的ですので、プリミティブな数値型に適用すると目的と少しずれますが、JavaScriptの型は寛容なので、制約の厳しいValue Objectを使うことで、良い感じに安全な型になると考えます。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>

// ValueObject 抽象ベースクラス
class ValueObject {
  constructor(value) {
    if (new.target === ValueObject) {
      throw new Error("Cannot instantiate abstract ValueObject directly");
    }
    this.value = value;
    Object.freeze(this); // immutable化
  }

  equals(other) {
    return other instanceof this.constructor && this.value === other.value;
  }

  toString() {
    return String(this.value);
  }

  valueOf() {
    return this.value; // 数値や比較で自動変換される場合
  }
}
// VONumber: 数値用VO
class VONumber extends ValueObject {
  constructor(value) {
    if (typeof value !== 'number' || !Number.isFinite(value)) {
      throw new Error(`${value} is not a valid number`);
    }
    super(value);
  }

  add(other) {
    if (!(other instanceof this.constructor)) {
      throw new Error("Operand must be same VO type");
    }
    return new this.constructor(this.value + other.value);
  }

  subtract(other) {
    if (!(other instanceof this.constructor)) {
      throw new Error("Operand must be same VO type");
    }
    return new this.constructor(this.value - other.value);
  }

  multiply(factor) {
    return new this.constructor(this.value * factor);
  }

  divide(divisor) {
    if (divisor === 0) throw new Error("Division by zero");
    return new this.constructor(this.value / divisor);
  }
}

const a1 = new VONumber(100);
const a2 = new VONumber(50);
let result = a1.add(a2);
console.log(result.toString());
// 150
    </script>
</body>
</html>

htmlファイルをWebブラウザで開き、ディベロッパーツールのコンソール※に150と出力されます。
※F12で開かれるブラウザが多い

クラスの定義がValueObject 抽象ベースクラスValueObjectとNumberの実装のVONumberの2つのクラスが定義しています。
VONumberを使うコードは以下の部分になります。

const a1 = new VONumber(100);
const a2 = new VONumber(50);
let result = a1.add(a2);
console.log(result.toString());
// 150

普通のNumberを使うと
let result = 100 + 50;
で済むところを、だいぶ回りくどいコードになります。

ただ、コンストラクタ引数がnumberであることを確認しているので、数値以外が代入されること防ぎます。
また、Value Objectですので、変数が不変であることが保証されているので、加算のaddメソッドは新しいVONumberオブジェクトを生成することになります。

Value Objectを使うと、変数の使いまわしができないので、おのずと変数の数が増えますが、意味ある値と変数が一対となりますので逆に管理しやすいかと思います。

・HTML/CSS/JavaScriptで開発
vscodeとchromeを使います。

・VSCodeのLive Preview拡張の使い方。
左ペインのhtmlファイルで右クリック→「プレビューの表示」を選びます。

コメント