はじめに
- コンストラクタを不可視にしたい
- 即時関数でもできるが、読みづらいので他の方法を考えてみた
- 可視性の境界をモジュール単位にするのがシンプルっぽい
やりかた
インスタンスを生成する関数だけエクスポートする。
Point.js
class Point {
constructor (x, y) {
this.x = x
this.y = y
}
}
// ファクトリーメソッド
function pointAt(x, y) {
return new Point(x, y)
}
// ファクトリーメソッドだけ export する
export { pointAt }
利用側
import { pointAt } from './Point.js'
let p = pointAt(0, 1)
使いどき
インスタンスの生成方法を強制したいとき。
Java の Integer クラス のように、頻繁に使われれる値オブジェクトをキャッシュするときなど。
例
2次元平面上の座標を表す Point
クラスを考えます。x
と y
の値を保持するだけのクラスです。同値判定を簡単に行うため、同じ座標の場合は常に同じオブジェクトの参照を返すようにしています。
Point.js
class Point {
constructor (x, y) {
this.x = x
this.y = y
}
}
// インスタンスを格納しておくマップ
const cache = {}
// ファクトリーメソッド
// 同じ x, y の組み合わせは常に同じインスタンスを返す
function pointAt (x, y) {
let key = x + ':' + y
if (key in cache) {
return cache[key]
} else {
let instance = new Point(x, y)
cache[key] = instance
return instance
}
}
export { pointAt }
利用側
import { pointAt } from './Point.js'
let p1 = pointAt(1, 2)
let p2 = pointAt(1, 2)
p1 === p2 // これが true を返すので、プリミティブな値のように扱える
Array.includes
は参照での比較を行うためプリミティブな値でしか使えませんが、このファクトリーメソッドで生成した Point
は同じ値は同じインスタンスなのでそのまま使えます。
利用例
import { pointAt } from './Point.js'
let arr = [pointAt(0, 1), pointAt(0, 2)]
let target = pointAt(0, 2)
arr.includes(target) // true を返す