ContainerJSに自動インジェクション機能を追加
WikipediaのDependency injectionのページに掲載されてちょっとやる気が出たので、ContainerJSに自動インジェクション機能を追加し、ver 0.4.0としてリリースしました。
自動インジェクションは、依存性注入が必要なプロパティに規定の値を指定しておくことで、「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( ); }); ... 略 });
これは偉大、あまりにも偉大(個人的に)。