cfneoの機能について

現在cfneo version0.01に盛り込もうと思っている機能について。

  • 簡易DI
  • UnitTest用のアサーション関数
  • レイヤを具体化したサンプル実装(examples-fizzbuzz
  • 独自Logger
  • アプリケーション生成

サンプル実装はもうひとつくらい欲しい気もしますね。(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のファイルではといった面倒な実装をせずにこのComponentManagerを使用できるようになっています。

<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コンポーネント間の依存関係が密結合にならないよう設計、実装すれば良いかなと。


今回はこれまで。