Service Locator + Visitor Patternのようなものでrequire地獄を避ける

勘違いがあったらツッコミください。

前提

JavaScriptには扱いやすい名前空間がない

Ruby や PHP は global な名前空間に簡単に class を置くことができ、必要に応じて module や namespace を使ってその影響範囲をコントロールすることができる。

対して JavaScript は伝統的にはすべて global leak させるか、特定のオブジェクトの中にぶら下げるかしかなかった。require / import 登場以降の時代は、読み込んだものに対して「任意の名前を付けることができる」ようになったので特定のコードを書いているファイルの中では自分で名前の衝突を避けるという作法になった。

逆に言うと思った通りの名前を思った通りにあちこちに影響させることはできない。例えば特定のディレクトリ以下にある class を全部読み込んでおけばアプリケーション内のどこからでもその名前を指定してオブジェクトを利用するといった使い方をするには一手間必要になる。そこで Service Locator ですよ。

Service Locatorの役割

Service Locator は単に名前とオブジェクトを紐づけてくれる KVS の役割を果たすオブジェクトだと思っておけばよい。

ServiceLocator.add('<name>', object) のようなメソッド 1 でオブジェクトの登録を行い、ServiceLocator.get('<name>') のようなメソッドでオブジェクトの取得を行う。ものすごく単純にインターフェイスだけ書くとこう。

class ServiceLocator {
  /**
   * @param {string} name
   * @param {object} object
   */
  static add (name, object) {
  }

  /**
   * @param {string} name
   * @return {object}
   */
  static get (name) {
  }
}

この Service Locator を使うと、ありとあらゆるところで

const Klass = require('klass')

を書きまくらなければいけないという問題を避けることができるのと、文字列からオブジェクトの取得ができるので、Ruby で言う Object.const_get() のようなものも実現できる。

requireしまくる人とaddしまくる人を消す工夫

上のような ServiceLocator をただ入れるだけだと、どこかで ServiceLocator.add() しまくる人は必要になる。ということは

const Klass = require('klass')
const Klass2 = require('klass2')
..

しまくる人も必要になる。

ただし、require される側に以下のようなコードを用意すると、この問題は解消できる。

class Klass {
  static get name () {
    return 'Klass'
  }

  static accept (locator) {
    locator.add(this.name, this)
  }
}

※ accept が汎用的すぎると感じたら(感じるよね?) locate などの名前でもよい。

こうしておくと、例えば以下のように Service Locator と組み合わせることで、上で書いた「特定のディレクトリ以下の class をすべてまとめて require しておく」ことを「いい具合に add を呼ぶ機能」で実現できる。

const glob = require('glob')
const ServiceLocator = require('service-locator')

glob(__dirname + '/sub/*.js', (err, files) => {
  files.forEach((file) => {
    const klass = require(file)
    klass.accept(ServiceLocator)
  })
})

やっていることは以下。

  • ServiceLocator で利用するオブジェクトに対して特定のルールを用意しておく
  • 特定のルールを用意しているオブジェクトに対し、ServiceLocator そのものを投げてしまう

お互いがお互いのインターフェイスを知っていればできる方法。上のコードでは accept メソッドの有無の確認などはしていないので、実践投入の際にはいろいろ考えて書くこと。

この程度の行数で済むなら Ruby や PHP のような感じなカジュアルさで class を使えるようになったと言ってもよさそう。

  1. add は set や register みたいな場合もあり得る 

ケータイを talby から re へ変更

結構前から壊れていた talby. いよいよ使いものにならないので雪の中、機種変にお出かけ。

結局ソニエリのフルチェンケータイ re のスリークシルバーってやつにした。いちばんメタルメタルしててかっこいいので。もう最近は新しい機能とか全然興味なくて、素材にしかこだわりがない。もっとメタル素材を採用した携帯が増えないかな。

フルチェンケータイ re | 携帯電話 | KDDI株式会社

ま、これは表のガワだけが金属で裏はプラッチックなので、やっぱりそのうちハゲハゲになるんだろうけど。

ちなみに1月いっぱいのキャンペーンに乗っかったので、端末代は1万円ほどお得になっている。

以下感想。

  • Web 周りの動作が速い(WINだから?でも処理速度も速くなってるような)
  • しかし基本の動作が遅い
  • フォントが見にくい
  • 持ちにくい
  • ボタンを押した感触が悪い

えーと。基本的にはあんまりいいとこない。機能で選ぶタイプの人にはお勧めしないな。

始めよう

otsune さんとこ経由で

知っておきたかったこと

こんなにも気持ちのいい文章は久しぶりに読みました。

パンツ2枚履いてる場合じゃない。

別に寒かったわけじゃないんだけど

今朝シャワーを浴びてぼーっと考えごとをしながら支度をしていたら、パンツ2枚履こうとしていた。びっくりして目が覚めた。

なんかどうも

3年前の雪のときより状況がひどいような気がするなぁ。。。

About

例によって個人のなんちゃらです