テストを考慮した singleton の ES6 export

テスト時の singleton を避けたい export

facebook/flux のサンプル準拠だと、Store や Dispatcher が singleton でテストを書きづらいことがあるので、普段使う singleton インスタンスと、テストで使う class オブジェクトを両方 export した。

import AppDispatcher, {Action, Payload} from '../dispatcher/AppDispatcher';
import * as Events from 'events';

const CHANGE_EVENT = 'change';

// 生クラスの export
export class AcmeStore extends Events.EventEmitter {
  dispatchToken: string;

  constructor() {
    super();
    this.dispatchToken = AppDispatcher.register(this.handleDispatch.bind(this));
  }

  handleDispatch(payload) {
    /* abstract */
  }

  private emitChange() {
    this.emit(CHANGE_EVENT);
  }

  addChangeListener(callback) {
    this.addListener(CHANGE_EVENT, callback);
  }

  removeChangeListener(callback) {
    this.removeListener(CHANGE_EVENT, callback);
  }
}

// singleton インスタンスの export
export default new AcmeStore();

import するとき

単純です。はい。そもそも伝統的な Klass.getInstance() 方式でも悪くはないんですけど、普段使いでメソッドコールしなくて済むほうが良いかなと。

let klass = require('./Klass').getInstance() とか書けないという気持ちもある。

普段使い

import AcmeStore from '../stores/AcmeStore';

AcmeStore.addChangeListener(function() {
  // hogehoge
});

テスト使い

import { AcmeStore } from '../stores/AcmeStore';

describe('AcmeStoreTest', function() {
  it('hogehoge', function() {
    let store = new AcmeStore();
  });
});

facebook/flux

ボイラープレート処理を BaseComponent, BaseStore 的なところに追いやれば、少なくとも薄いタイプの亜種 flux は使わなくても十分なのではと感じ始めた今日この頃。

isomorphic 全部入りとかになると話が違ってくるとは思うんだけど、fluxible とか