在Java中,有這樣一段老代碼:
Java代碼
class Round{
public void drawRound(); //畫圓
}
現在新代碼希望能和它共存,使用一個Person的對象來控制,隻不過,可能drawRound,也可能drawRect啊:
Java代碼
class Rect{
public void drawRect(); //畫方
}
好,廢話少說,我先想到瞭Adapter模式:
Java代碼
interface Drawable{
public void draw();
}
public class RoundAdapter implements Drawable{
private Round round;
public void draw(){
round.drawRound();
}
}
public class RectAdapter implements Drawable{
private Rect rect;
public void draw(){
rect.drawRect();
}
}
然後,我再引入一個Person對象,就能搞定這一切瞭:
Java代碼
class Person{
private Drawable adapter;
public Person(Drawable adapter){
this.adapter = adapter;
}
public void draw(){
this.adapter.draw();
}
}
Drawable rou = new RoundAdapter();
Drawable rec = new RectAdapter();
new Person(rou).draw(); //畫圓
new Person(rec).draw(); //畫方
想必到此已經讓你煩瞭,一個Adapter模式的最簡單例子。再多看一看,這個模式的核心是什麼?接口!對,正是例子中的Drawable接口——正是在接口的規約和領導下,我們才能讓畫圓和畫方都變得那麼聽話。
現在JavaScript中,也有這樣一段老代碼:
Java代碼
function Round(){
this.drawRound = function(){
alert("round");
}
}
我也想依葫蘆畫瓢,但是JavaScript沒有接口瞭,怎麼辦?
……
接口的作用是什麼?是對類的行為的規約,可是JavaScript的行為是動態的,無法用簡單純粹的接口來實現、來約束,即便模擬出這樣一個接口(參見《JavaScript Design Pattern》),在此又有必要使用它麼?強行做出一個接口來,這不是和JavaScript的初衷相違背瞭嗎?
再回到這個問題上面,我原本希望Person的對象可以調用一個統一的draw方法,隻是在通過構造Person對象的時候,傳入一個不同實現的Drawable對象,做出瞭不同約束下的實現。
那麼,JavaScript中,不僅僅方法的調用者可以作為一個參數傳入,方法本身也可以作為參數傳入(即所謂方法閉包),這樣,所有變化點都控制在這個參數之中,不也實現瞭我想要的接口規約的效果嗎:
Java代碼
function Rect(){
this.drawRect = function(){
alert("rect");
}
}
function Person(obj){
//obj參數的格式:{doWhat,who}
for(var i in obj){
this.doWhat = i;
this.who = obj[i];
break;
}
this.draw = function(){
this.who[this.doWhat].call(this.who);
};
}
var rou = { drawRound : new Round() };
var rec = { drawRect : new Rect() };
(new Person(rou)).draw();
(new Person(rec)).draw();
寫到這裡,我覺得很開心:
在Java中,通過接口的規約和適配器的幫助,我將變化點封裝在Person構造器的參數之中;
JavaScript中,沒有瞭接口、脫離瞭適配器的幫助,我依然能將變化點封裝在Person的構造器參數之中。
作者“四火的BLOG”