読者です 読者をやめる 読者になる 読者になる
無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

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

ContainerJSに自動インジェクション機能を追加

JavaScript DIコンテナ

WikipediaのDependency injectionのページに掲載されてちょっとやる気が出たので、ContainerJSに自動インジェクション機能を追加し、ver 0.4.0としてリリースしました。

Google Code - ContainerJS

自動インジェクションは、依存性注入が必要なプロパティに規定の値を指定しておくことで、「inject」の指定なしに自動で依存コンポーネントの探索と注入を行う機能です。(なのであんまり自動ではないかもしれない。)

  • 具体的には、値として「container.Inject」または「container.Injects」を指定しておけば、依存性注入対象としてマークされます。
  • マークされたプロパティには、以下のルールに従ってコンテナから依存コンポーネントが探索され、注入されます。
    • 「container.Inject」が指定されている場合 ... コンポーネントの「プロパティ名」にマッチするコンポーネント
    • 「container.Injects」が指定されている場合 ... コンポーネントの「プロパティ名」にマッチするコンポーネントの配列
    • 「container.Inject("name")」が指定されている場合 ... 引数で指定された名前にマッチするコンポーネント(「container.Injects("name")」はその配列版です。)
    • 「container.Inject( type )」が指定されている場合 ... 引数で指定されたTypeにマッチするコンポーネント(「container.Injects( type )」はその配列版です。)
  • 「Inject」によるプロパティインジェクションとの併用も可能。両方が指定された場合、「Inject」で指定された値が有効となります。

サンプルは以下。

var stdout = document.getElementById( "stdout" );

// クラス
function Kitten() {
  // name,ageをコンテナから探索するようマーク。
  this.name = container.Inject;
  this.age = container.Inject( "age" );
}
Kitten.prototype = {
   toString: function () { return this.name + ":" + this.age; }
};

var c = new container.Container( function( binder ) {
  
  binder.bind( Kitten ).to( "kitten" );

  binder.bindInstance( "mii" ).to( "name" );
  binder.bindInstance( 2 ).to( "age" );
});

//コンポーネントを取得
//自動インジェクション対象としてマークされている属性は、
//コンテナから値が探索され代入されている。
var kitten = c.get( "kitten" );
stdout.innerHTML += kitten.toString(); // "mii:2"

実行結果はこちら

さて

さて、これでjijiで使われている以下のコードが、

fx.container = new container.Container( function( binder ){

  // App
  binder.bind( fx.Application ).to( "app" ).inject({
    pageManager: container.component("pageManager"),
    sideBar:     container.component("sideBar")
  });

  // page manager
  binder.bind( util.PageManager ).to( "pageManager" ).initialize( function( obj, container ) {
      obj.init( container.gets("pages"));
  });

  // pages
  binder.bind( fx.ui.pages.RtSettingPage ).to( "pages" ).inject({
   id : "rt_setting",
   elementId : "page-rt-setting",
   agentSelector: container.component("rtSettingAgentSelector"),
   processServiceStub: container.component("processServiceStub"),
   topicPath: container.component("topicPath"),
   tradeEnable: container.component("tradeEnable"),
   dialog : container.component("dialog")
  }).initialize( function( obj, container ) {
    obj.initialize( );
  });
  binder.bind( fx.ui.pages.AgentEditorPage ).to( "pages" ).inject({
   id : "agent_edit",
   elementId : "page-agent-edit",
   agentServiceStub: container.component("agentServiceStub"),
   agentFileListTable: container.component("agentFileListTable"),
   topicPath: container.component("topicPath"),
   dialog : container.component("dialog")
  });
  binder.bind( fx.ui.pages.BtCreatePage ).to( "pages" ).inject({
    id : "bt_create",
    elementId : "page-bt-create",
    agentSelector: container.component("btCreateAgentSelector"),
    processServiceStub: container.component("processServiceStub"),
    rateServiceStub: container.component("rateServiceStub"),
    topicPath: container.component("topicPath"),
    sideBar: container.component("sideBar"),
    dialog : container.component("dialog")
  }).initialize( function( obj, container ) {
    obj.initialize( );
  });
  ... 略
});

次のように書けるようになるはず。

fx.container = new container.Container( function( binder ){

  // App
  binder.bind( fx.Application ).to( "app" )

  // page manager
  binder.bind( util.PageManager ).to( "pageManager" ).initialize( function( obj, container ) {
      obj.init( container.gets("pages"));
  });

  // pages
  binder.bind( fx.ui.pages.RtSettingPage ).to( "pages" ).inject({
   id : "rt_setting",
   elementId : "page-rt-setting",
  }).initialize( function( obj, container ) {
    obj.initialize( );
  });
  binder.bind( fx.ui.pages.AgentEditorPage ).to( "pages" ).inject({
   id : "agent_edit",
   elementId : "page-agent-edit"
  });
  binder.bind( fx.ui.pages.BtCreatePage ).to( "pages" ).inject({
    id : "bt_create",
    elementId : "page-bt-create"
  }).initialize( function( obj, container ) {
    obj.initialize( );
  });
  ... 略
});

これは偉大、あまりにも偉大(個人的に)。