無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

アノテーションを使ってインターセプタを適用する

JavaScriptでインターセプトの方法だと、インスタンスの生成ごとにapplyInterceptor()行う必要があって面倒です。クラス定義にアノテーションを書いておくと勝手にインターセプタを設定してくれるようにしたい!

アノーテョン

とはいえ、JavaScriptアノテーションはありません。そこで、関数やクラス関数に meta 属性を勝手に作って、そこにアノテーションを書くことにします!

// アノテーションするクラス
function KittenService(  ) {}
KittenService.prototype = {
  run:  function() {
    stdout.innerHTML += "run!<br/>";
  },
  stop: function() {
    stdout.innerHTML += "stop!<br/>";
  },
  jump: function() {
    stdout.innerHTML += "jump!<br/>";
  }
}

// これを関数のアノテーションとしよう!
KittenService.prototype.jump.meta = {
   echo: {}
}
KittenService.prototype.stop.meta = {
   echo: {}
}
// クラスのアノテーションはこうする!
KittenService.prototype.meta = {
   intercept: true
}
// フィールドのアノテーションはこれから考える!

「フィールドのアノテーションは?」とか、「関数上書きしたら消え去りそう」とか、いろいろつっこみどころはありますがとりあえずはこれで。

サービスファクトリ

アノーテョンができた?ので、次はサービスファクトリです。「サービスファクトリ」はオブジェクトを生成するクラスで、このときアノテーション参照して、必要であればインターセプタを設定します。

/**
 * サービスファクトリ
 * @param {Object} recipe インターセプタのハッシュ
 */
function ServiceFactory( recipe ) {
  this.recipe = recipe;
}
ServiceFactory.prototype = {

  /**
   * クラスのインスタンスを生成する。
   * @param {Object} clazz クラス
   * @param {Object} arg コンストラクタ引数
   */
  create: function( clazz) {

    // インスタンス生成
    var obj = new clazz();

    // interceptアノテーション付きのクラスにのみインターセプタを適用。
    if ( obj.meta && obj.meta.intercept ) {
        for ( var key in obj ) {
            if ( typeof obj[key] != "function" ) {
              continue;
            }
            if ( !obj[key].meta ) {
              continue;
            }
            for ( var meta in obj[key].meta ) {
              // 関数に付いているアノテーションと同じ名前のインターセプタがレシピにあれば登録する。
              if (!this.recipe[meta]) { continue; }
              var thiz = this;
              (function() {
                var interceptor = thiz.recipe[meta];
                var x = key;
                var original = obj[key];
                obj[x] = function( ) {
                    // インターセプターを実行する関数に置き換える。
                    return interceptor( x, obj, original, arguments );
                }
                obj[x].meta = original.meta;
              })();
            }
        }
    }
    return obj;
  }
}

使ってみる

サービスファクトリを使うと、こんな感じでインターセプタを適用したオブジェクトを生成できます。

// サービスファクトリを生成
// 引数でインターセプタのハッシュを指定。
// この場合、echoが付いていれば関数呼び出しの前後で関数名を表示する。
var sf = new ServiceFactory( {
  echo: function( f, target, original, arguments ) {
    stdout.innerHTML += "start. " + f + "<br/>";
    try {
      return original.apply( target, arguments );
    } finally {
      stdout.innerHTML += "end. " + f + "<br/>";
    }
  }
});

// サービスの作成
var service = sf.create( KittenService );
service.run();
service.stop();
service.jump();

確認はこちら。