Transfer の機能にある、decorator とはなんだろうか。
どこかで聞いたような気がしたんだけど、オブジェクト指向に出てくるデコレータパターンかな。
オブジェクトの振る舞いを自由に変更できるということか。
例のごとく、ドキュメントを読んでも、さっぱりわからない。
悪戦苦闘の結果に導き出した答えが、「Transfer のオブジェクトの振る舞いを変更するための仕組み」。
Transfer のオブジェクトは、Transfer.xml の object タグの情報を元に、自動で生成される。Transfer.xml で設定できること以外は、そのオブジェクトに対しては、ブラックボックス状態だ。
そこで、この transfer.com.TransferDecorator の出番となる。
うまい例が思いつかなかったので、適当な仮定をしてみる。仮に、全商品一律2割引セールをする。
いろいろとやり方はあるが、TransferDecorator を使うために、商品をカートに入れる際に、商品の価格を2割引して登録することにする。
デコレータのコンポーネントを作る。
/ shopping / model / decorator / userdata / CartData.cfc に transfer.com.TransferDecorator を継承してコンポーネントを作成する。
当然、場所はどこでも構わない。
次に、実際に userdate.CartData の自動生成されたオブジェクトファイルから、価格に関する関数を持ってくる。
これまでの設定状態だと、shopping / model / data / transfer に userdata.CartData で始まるファイルがあるはずだ。
いくつかあるかもしれないが、とりあえず、どれかを開き、setPrice 関数をコピーして、先ほどの デコレータコンポーネントにペーストする。その関数を変更することによって、オーバーライドして、振る舞いを変えるわけだ。
<cffunction name="setPrice" access="public" returntype="void" output="false">
<cfargument name="Price" type="numeric" required="true">
<cfset var newPrice = Int(arguments.Price * 0.8)>
<cfset getTransferObject().setPrice(newPrice)>
</cffunction>
次に、Transfer オブジェクトにデコレータを登録する。
コードをゴリゴリ書いて実装するのか?と思ったけど、実にスマートなやり方があった。
Transfer.xml の object タグの属性をくっつけるだけである。
<object name="CartData" table="CARTDATA" decorator="shopping.model.decorator.userdata.CartData">
これだけで userdata.CartData に対して生成された TransferObject は shopping.model.decorator.userdata.CartData になっている。
つまり、variables.transfer.get("userdata.CartHeader", sessionId) などの返値は、TransferObject なわけだが、デコレータ設定があれば、返値が shopping.model.decorator.userdata.CartData なのである。うん、説明が難しい。
これで、カートに入れたときに、全商品、価格が自動的に2割引されるようになる。
ところで、この Transfer.xml では、以前書いた、ENTITY タグが使えなかった。余計なタグは一切認めないのだろうか。かなりがっかりである。