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