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

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

バインドメソッド

JavaScriptで動くDIコンテナの解説その2。

バインドメソッドは、登録済みコンポーネントの任意の関数をコンポーネントとして登録する機能です。

  • モデルのリスナーとしてUIコンポーネントの関数を登録。
    • →変更通知を受けてUIを更新。
  • 通信エラーのコールバック関数としてUIコンポーネントの関数を登録。
    • →エラー発生時にダイアログを表示

といった使い方をイメージしています。UI層とそれ以外の層の関連づけをコンテナで行うことで、レイヤー間の結合を疎にできます。

使用方法

バインドメソッドはtoFunction()を使用して登録します。

  • 引数で関数の所有者であるコンポーネント名と関数名を指定します。
  • コンテナからコンポーネントを取得するのと同じ方法で関数を取得し、実行することができます。
    • 関数には、それの所有者であるコンポーネントが封入されているので、内部でthisが使えます。
    • 引数もOK。
  • スコープやインジェクションの指定を行うことはできません。(toFunction()は戻り値を返しません。)
// テスト用のクラス。
function Kitten( ) {
  this.name = name;
}
Kitten.prototype = {
  getName: function() { return this.name; },
  setName: function(name) { this.name = name; }
}

var c = new container.Container( function( binder ) {
  // コンポーネントを登録
  binder.bind("mii").to( Kitten ).inject( { name: "mii" } );
  
  // バインドメソッドを登録
  binder.bind( "get" ).toFunction( "mii", "getName" );
  binder.bind( "set" ).toFunction( "mii", "setName" );
});

var mii = c.get("mii");
stdout.innerHTML += mii.getName() + "</br>"; // nii

// バインドメソッドの取得と実行。
var get = c.get("get");
var set = c.get("set");
stdout.innerHTML += get() + "</br>"; // mii

set("tora"); // 引数も使える。
stdout.innerHTML += get() + "</br>"; // tora

// コンポーネント mii のAPIが呼び出されているので、miiの名前が更新されている
stdout.innerHTML += mii.getName() + "</br>"; // tora

確認はこちら

具体例

実用的な例としてモデルの更新リスナをバインドメソッドで登録してみます。

// モデル兼コントローラ
function Kitten( ) {
  this.state = "stop";
  this.listeners = [];
}
Kitten.prototype = {
  run:  function() {
    this.setState("running");
  },
  stop: function() {
    this.setState("stop");
  },
  jump: function() {
    this.setState("jump!");
  },
  // 状態を変更する。
  setState: function( state ) {
    this.state = state;
    // 変更したらリスナに通知。
    for ( var i = 0; i < this.listeners.length; i++ ) {
      this.listeners[i].call( null, state );
    }
  }
}

// 猫の状態表示UI
function KittenStateView( elmId ) {
  this.elmId = elmId;
}
KittenStateView.prototype = {
  // 状態が変わったらUIを更新する。
  onKittenStateChanged : function( newState ) {
    document.getElementById( this.elmId ).innerHTML = newState;
  }
}

// コンテナ
var c = new container.Container( function( binder ) {

  // 猫
  binder.bind("mii").to( Kitten ).inject( {
    // リスナとして"onKittenStateChanged"の名を持つコンポーネントを設定。
    "listeners": container.components( "onKittenStateChanged" )
  } );

  // コンポーネントを登録
  binder.bind("view1").to( KittenStateView ).inject( { elmId: "view1" } );
  binder.bind("view2").to( KittenStateView ).inject( { elmId: "view2" } );
  binder.bind("view3").to( KittenStateView ).inject( { elmId: "view3" } );

  // バインドメソッドを登録
  binder.bind( "onKittenStateChanged" ).toFunction( "view1", "onKittenStateChanged" );
  binder.bind( "onKittenStateChanged" ).toFunction( "view2", "onKittenStateChanged" );
  binder.bind( "onKittenStateChanged" ).toFunction( "view3", "onKittenStateChanged" );
});

var mii = c.get("mii"); // これのAPIを呼び出すと 状態の変更→UIの更新が行われる。

確認はこちら