Javascript は、動的に型付けされたプロトタイプベースの言語です。テンプレート メソッドはデザイン パターンであるため、言語に依存しませんが、その実装は言語によって異なる場合があります。
JavaScript の場合、また Ruby などの他の動的型付け言語の場合、動的リンクは委譲によって行われるため、抽象クラスとインターフェースはあまり意味がありません。(メソッド呼び出しは、プロトタイプが要求を処理できるようになるまで、継承ツリーの上位レベルに伝達されます)。これは、任意のインスタンスで任意のメソッドを潜在的に呼び出すことができることを意味するダックタイピングと組み合わせて、明示的な契約の必要性を回避します。これは、クラスベースの言語では、特定のタイプで可視である宣言されたメソッドによって定義されます。
したがって、パターンを実装するには、親のプロトタイプ ビルド メソッド (そのメソッドがテンプレートになります) で存在しないメソッドを呼び出し、サブクラスでそのメソッドを実装するだけです。
function PropertyDecorator()
{
this.build = function()
{
var decoration=this.decorate();
return "The decoration I did: "+decoration;
};
}
//we set the parent (those prototype that instances of this class will delegate calls to)
OpenButtonDecorator.prototype = new PropertyDecorator();
function OpenButtonDecorator()
{
this.decorate = function()
{
return "open button";
};
}
SeeButtonDecorator.prototype = new PropertyDecorator();
function SeeButtonDecorator()
{
this.decorate = function()
{
return "see button";
};
}
var decorators=Array(new SeeButtonDecorator(),new OpenButtonDecorator());
for (var decorator in decorators){
document.writeln(decorators[decorator].build());
}
メソッドのディスパッチは次のように行われます。
- インスタンスにメソッドが呼び出されていますか?
- いいえ -> 呼び出しを親 (プロトタイプ) に委譲して繰り返します。
- はい->暗黙のオブジェクト(最初に呼び出しを受け取ったもの)のコンテキストでメソッド本体を実行します。
そのため、 new SeeButtonDecorator().build() を呼び出すと、まずインスタンスでビルド メソッドを実行しようとします。インスタンスで定義されていないため、メソッド呼び出しはインスタンスの親に委譲されます。この場合、SeeButtonDecorator プロトタイプ (このプロトタイプ) にはメソッドも含まれていないため、呼び出しをその親 (PropertyDecorator) に委譲します。PropertyDecorator には、build()
メソッドがあります。
function PropertyDecorator()
{
this.build = function()
{
var decoration=this.decorate();
return "The decoration I did: "+decoration;
};
}
実行すると、build
メソッドの本体は新しい SeeButtonDecorator() のコンテキストで評価されます。decorate()
SeeButtonDecorator() 関数 (そのプロトタイプ) で定義されているため、インスタンス自体にはメソッドがありません。さて、今回は呼び出しがインスタンス プロトタイプに委譲され、最終的にdecorate() メソッドが取得されます。
function SeeButtonDecorator()
{
this.decorate = function()
{
return "see button";
};
}
メソッドはインスタンスのコンテキストで再び実行され、文字列を返し、戻るまでコール スタックにフォールバックします。
The decoration I did: see button