JavaScriptの動的な性質を利用したDOM要素ファクトリ
JavaScriptは動的な言語である。例えば、与えられた文字列から、その文字列に対応するメソッドを簡単に呼び出せる。そこで、この性質を利用したDOM要素のファクトリを作ってみた。
var Factory = function(){}; Factory.prototype = { create: function(name){ if(typeof(this["create" + name]) == "function"){ var args = []; for(var i = 1; i < arguments.length; i++){ args.push(arguments[i]); } return this["create" + name].apply(this, args); }else{ return this.createElement.apply(this, arguments); } }, createElement: function(tagName, options){ var element = document.createElement(tagName); options.className && (element.className = options.className); options.innerHTML && (element.innerHTML = options.innerHTML); options.parent && options.parent.appendChild(element); return element; }, createA: function(options){ var element = this.createElement("A", options); options.href && (element.href = options.href); return element; }, createBorderDIV: function(options){ var element = this.createElement("DIV", options); element.style.border = "solid 1px"; return element; } }
呼び出し方は、こんな感じ。
var factory = new Factory; var gd = factory.create("BorderDIV", {parent: document.body, innerHTML: "border"}); var d = factory.create("DIV", {parent: gd, innerHTML: "test"}); var a = factory.create("A", {parent: d, innerHTML: "llamerada", href: "http://d.hatena.ne.jp/llamerada"});
すると、こんなHTMLが作られる。
<div style="border: 1px solid ;"> border <div>test<a href="http://d.hatena.ne.jp/llamerada">llamerada</a> </div> </div>
Factoryクラスのcreateメソッドの基本機能は、tagNameとoptionsを引数にとってtagName要素を生成することである。ただし、createBorderDIVやcreateAなど、tagNameに該当するメソッドが存在する場合は、それらのメソッドが呼び出される。tagNameに該当するcreateメソッドがないときは、デフォルトのメソッドであるcreateElementが呼び出される。
このように記述することの利点は、Factoryクラスのクライアントが利用するメソッドをcreateメソッドに限定されることによる、保守性と柔軟性の向上である。
なお、この手法は、Rubyのmethod_missingの考え方に影響を受けている。method_missingは、メソッドを呼び出した際に、該当するメソッドがない場合に呼び出されるメソッドである。このFactoryクラスでは、method_missingは、該当するtagNameがない場合に呼び出されるcreateElementメソッドに相当する。
このアプローチを発展させて、tagNameにさらに複雑な処理を埋め込めこともできる。例えば、tagNameの文字列を解析して、tagNameがBorderを含むならば、枠で囲む処理を加えることにして、個別にcreateBorderDIVなどを定義しない方法も可能である。