cfneoの機能について
現在cfneo version0.01に盛り込もうと思っている機能について。
サンプル実装はもうひとつくらい欲しい気もしますね。(Coldfusion8にはデフォルトでDerbyが組み込まれているようです)
それぞれを簡単に説明すると。。。(と書きながら、ただの脳内まとめ&メモ)
簡易DI
簡易DIですが、CFMLの仕様としてコンポーネント名(Javaで言うClass名)はすべて「文字列で指定」しないといけません。つまりリフレクションです。リフレクションなのですが、CFMLのコンポーネント(以下、CFコンポーネント)はそのCFCファイルが置かれているフォルダとなる(例えば、http://hoge.hoge/hogeapp/hogecomp/hoge.cfcというコンポーネントならパッケージは"hogeapp.hogecomp.hoge"になる)ため、hogeappをベースにhogeapp2を作ろうとした場合、"hogeapp"という文字列を書き直さなければなりません。
コードにするとこんな感じです。
<!---// hogeappのコンポーネントのインスタンスを作る(cfsetで作った場合) //---> <cfset obj=CreateObject("component", "hogeapp.hogecomp.hoge") /> <!---// hogeapp2のコンポーネントのインスタンスを作る(cfsetで作った場合) //---> <cfset obj2=CreateObject("component", "hogeapp2.hogecomp.hoge") /> <!---// オマケとして、hogeappのコンポーネントのインスタンスをCFMLっぽくタグで作ってみる(cfobject) //---> <cfobject component="hogeapp.hogecomp.hoge" name="obj" />
リファクタリングしてくれるIDEも今のところ、僕は知らないです><
かと言って、CFコンポーネントを使わないという選択肢を選ぶと、実装は相当ハードになります。「.java禁止JSPしか使っちゃいけないエンタープライズJava開発」みたいになります。
そこで、http://hoge.hoge/hogeapp/の直下にApplication.cfcというCFコンポーネントを作成します。(これもこれで結構キモイCFコンポーネントですが)このApplication.cfcはいわばjavax.servlet.ServletのCFラッピングといった感じのシロモノなのですが(かと言って、doGet等のMethodがある訳でもないです)、ここで以下のようにアプリケーション名を定義できます。
<cfcomponent> <cfset This.name="appname" /> <!---// ... //---> </cfcomponent>
この一文を記述する事で、APPLICATIONスコープのApplicationNameという属性に指定したアプリケーション名(上の例だとappnameという文字列)が設定されます。そこで前述のインスタンスを生成する(キモイ)CFMLのコードを以下のように書けるようになります。
<cfset obj=CreateObject("component", "#APPLICATION.ApplicationName#.hogecomp.hoge" />
ドメインのルートではなく、1階層低いところをアプリケーションのルートとして指定しても、この方法なら複数のアプリケーションを並列で配置することが可能です。(本番稼動時にその必要があるかどうかはよく分かりませんが、開発時はWebルートの下にいくつかアプリケーションを分けて作れるようになっていた方が全然楽です)
で、これを利用してcfneoにはComponentManagerというCFコンポーネントを用意してあります。
これはあれです、S2Containerみたいなヤツでw、MethodはgetComponent(componentName)だけです。
また、cfneoの基幹部分で実装しているApplication.cfcにpublicスコープのgetComponentManager()というメソッドがあります。中身は、このComponentManagerのインスタンスを生成して返却しているだけなのですが、これをApplication.cfc上で実装する事で以下のような.cfmのファイルでは
<html> <body> <cfset VARIABLES.obj=getComponentManager().getComponent("hogecomp.hoge") /> </body> </html>
前述しましたAPPLICATION.ApplicationNameはComponentManager内部で勝手に解決してくれます。
また、CFコンポーネントのインスタンスを生成する際に、comMgrという属性にComponentManager自身のインスタンスをセットしていますので、CFコンポーネント内部からもこのComponentManagerを使用する事ができます。
<cfcomponent> <cffunction name="hogefunc" access="public" returntype="void"> <cfset var obj=THIS.comMgr.getComponent("hogecomp.hoge") /> </cffunction> </cfcomponent>
DIを名乗るにはMethodのインターフェイス定義とかないじゃん、どーなってんの?とか思ったのですが、cfinterfaceは正直使うメリットを全く感じないので*1考えない事にしました><
あとは、実際に作るアプリケーションでCFコンポーネント間の依存関係が密結合にならないよう設計、実装すれば良いかなと。
今回はこれまで。