CFMLでデザインパターン実装(1.AbstractFactory)
最近、Coldfusion8の評価をしようとあれこれ調べておりますが、CFでどこまでGoFのデザインパターンが使えるのか気になりました。Javaと違って動的型付けっぽいので適用させる意味があまり無いパターンもあるのは間違いないと思うのですが、AbstractFactoryを実装してみます。
まず、基本となる機能をJavaで実装したもの。
Java-1:呼び元(TestCaseをそのままmain扱い)
public void test() { try { String returnValue = null; returnValue = this.getSaid(AbstractFactory.HELLO_WORLD); System.out.println(returnValue); returnValue = this.getSaid(AbstractFactory.GOOD_BY_WORLD); System.out.println(returnValue); } catch (Exception e) { e.printStackTrace(); fail(); } } private String getSaid(String key) { AbstractFactory factory = AbstractFactory.getFactory(key);; HelloWorld hello = factory.createHelloWorld(); return hello.say(); }
Java-2:Abstract Factory
public abstract class AbstractFactory { public static final String HELLO_WORLD = "hello"; public static final String GOOD_BY_WORLD = "good-by"; public static AbstractFactory getFactory(String key) { AbstractFactory factory = null; if (key.equals(HELLO_WORLD)) { factory = new HelloWorldFactory(); } else if (key.equals(GOOD_BY_WORLD)) { factory = new GoodByWorldFactory(); } return factory; } abstract public HelloWorld createHelloWorld();
Java-3:Concrete Factory
public class HelloWorldFactory extends AbstractFactory { @Override public HelloWorld createHelloWorld() { return new HelloWorld(); } }
Java-4:Factoryまで使って生成したいHelloWorld。
public class HelloWorld { private String word; public HelloWorld() { this.word = "Hello, World."; } public String say() { return this.getWord(); } public String getWord() { return word; } public void setWord(String word) { this.word = word; } }
Java-5:上記の(1)を実行すれば、以下がコンソールに出力される。
Hello, World.
Good-By, World.
※いちおうGoodByWorldというクラスも作っていた為、余分な出力がありました。
(考えずに貼り付けた私が一番悪いです)
このJavaコードをまんまCFMLに展開。
cf-1:呼び元(ブラウザで見るしかないのでCFMで実装)
<html> <head> <title>Gof design pattern@CFML</title> </head> <body> <cfoutput> <cftry> <hr/> <h5>Hello, world.</h5> <!---// Get factory instance. //---> <cfinvoke method="getFactory" component="cftest.gof.abstract_factory.AbstractFactory" returnvariable="Variables.ret"> <cfinvokeargument name="key" value="hello"/> </cfinvoke> <!---// Get HelloWorld. //---> <cfset Variables.obj=Variables.ret.createHelloWorld()/> <cfinvoke method="say" component="#Variables.obj#" returnvariable="Variables.returnValue"/> Return value of getter:[#Variables.returnValue#])<br/> Direct access:[#Variables.obj.word#] <hr/> <!---// Get factory instance. //---> <cfinvoke method="getFactory" component="cftest.gof.abstract_factory.AbstractFactory" returnvariable="Variables.ret"> <cfinvokeargument name="key" value="good-by"/> </cfinvoke> <!---// Get HelloWorld. //---> <cfset Variables.obj=Variables.ret.createHelloWorld()/> <cfinvoke method="say" component="#Variables.obj#" returnvariable="Variables.returnValue"/> Return value of getter:[#Variables.returnValue#])<br/> Direct access:[#Variables.obj.word#] <cfcatch> <cfdump label="#cfcatch.Message#" var="#cfcatch#"/> </cfcatch> </cftry> </cfoutput> </body> </html>
cf-2:Abstract Factory
<cfcomponent output="false"> <cffunction name="getFactory" access="public" returntype="cftest.gof.abstract_factory.AbstractFactory"> <cfargument name="key" type="string" required="true"/> <cfset var factory=""/> <cfif Arguments.key is "hello"> <cfobject name="factory" component="cftest.gof.abstract_factory.HelloWorldFactory"/> <cfelseif Arguments.key is "good-by"> <cfobject name="factory" component="cftest.gof.abstract_factory.GoodByWorldFactory"/> </cfif> <cfreturn factory/> </cffunction> <cffunction name="createHelloWorld" access="public" returntype="cftest.gof.common.HelloWorld"> <!---// Interface defined. //---> <cfreturn/> </cffunction> </cfcomponent>
cf-3:Concrete Factory
<cfcomponent output="false" extends="cftest.gof.abstract_factory.AbstractFactory"> <!---// @Override //---> <cffunction name="createHelloWorld" access="public" returntype="cftest.gof.common.HelloWorld"> <!---// Interface defined. //---> <cfset var obj=""/> <cfobject name="obj" component="cftest.gof.common.HelloWorld"/> <cfinvoke method="HelloWorld" component="#obj#"/> <cfreturn obj/> </cffunction> </cfcomponent>
cf-4:Factoryまで使って生成し(ry
<cfcomponent output="false"> <!---// コンストラクタ風 //---> <cffunction name="HelloWorld" access="public" returntype="void"> <cfinvoke method="setWord"> <cfinvokeargument name="word" value="Hello, World."/> </cfinvoke> </cffunction> <cffunction name="say" access="public" output="false" returntype="string"> <cfreturn This.getWord()/> </cffunction> <cffunction name="setWord" access="public" output="false" returntype="void"> <cfargument name="word" type="string" required="true"/> <cfset This.word=Arguments.word/> </cffunction> <cffunction name="getWord" access="public" output="false" returntype="string"> <cfreturn This.word/> </cffunction> </cfcomponent>
cf-5:上記の(1)を実行すれば、以下がブラウザに出力される。
Hello, world.
Return value of getter:[Hello, World.])
Direct access:[Hello, World.]
- -
Return value of getter:[Good-by, World.])
Direct access:[Good-by, World.]