子產品模式
道格拉斯所說的子產品模式則是為單例建立私有私有變量和特權方法。所謂單例,指的就是隻有一個執行個體的對象。按照慣例,JavaScript是以對象字面量的方式來建立單列對象的。
var singleton = {
name: value,
method: function() {
}
}
子產品模式通過為單例添加私有變量和特權方法能夠使其得到增強,其文法形式如下:
var singleton = function() {
var privateVariable = 10;
function privateFunction() {
return false;
}
return {
publicVariable: true,
publicMethod: function() {
privateVariable++;
return privateFunction();
}
}
}();
這個子產品模式使用了一個傳回對象的匿名函數。在這個匿名函數内部,首先定義了私有變量和函數。然後,将一個對象字面量作為函數的值傳回。傳回的對象字面量中隻包含可以公開的屬性和方法。由于這個對象是在匿名函數内部定義的,是以它的公有方法有權通路私有變量和函數 。從本質上來講,這個對象字面量定義的是單例的公共接口。這種模式在需要對單例進行某些初始化,同僚又需要維護其私有變量時是非常有用的,例如:
var application = function() {
var components = new Array();
components.push(new BaseComponenet());
return {
getComponentCount: function() {
return components.length;
},
registerComponenet: function(component) {
if (typeof component == "object") {
components.push(component);
}
}
};
}();
在Web應用程式中,經常需要使用一個單例來管理應用程式的資訊。這個簡單的例子建立了一個用于管理元件的application對象。在建立這個對象的過程中,首先聲明一個私有的components數組,并向數組中添加了一個BaseComponent的新執行個體。而傳回對象的getComponentCount() 和 registerComponent()方法,都是有權通路資料components的特權方法。前者隻是傳回已注冊的元件數目,後者用于注冊新元件。
簡言之,如果必須建立一個對象并以某些資料對其進行初始化,同時還要公開一些能夠通路這些私有資料的方法,那麼就可以使用子產品模式。以這種模式建立的每個單例都是Object的執行個體,因為最終要通過一個對象字面量來表示它。事實上,這也沒有什麼;畢竟,單例通常都是作為全局對象存在的,我們不會将它傳遞個一個函數。是以,也就沒有什麼必要使用instanceof操作符來檢查其對象類型了。
增強的子產品模式
有人進一步改進了子產品模式,即在傳回對象之前加入對其增強的代碼。這種增強的子產品模式适合那些單例必須是某種類型的執行個體,同僚還必須添加某些屬性和(或)方法對其加以增強的情況。看下面的例子:
var singleton = function() {
var components = new Array();
function privateFunction() {
return false;
}
var object = new CustomType();
object.publicProperty = true;
object.publicMethod = function() {
privateVariable++;
return privateFunction();
}
return object;
}();
如果前面示範子產品模式的例子中的application對象必須是BaseComponent的執行個體,那麼可以使用以下代碼:
var application = function() {
var components = new Array();
components.push(new BaseComponent());
var app = new BaseComponent();
app.getComponentCount = function() {
return components.length;
};
app.registerComponent = function(component) {
if (typeof component == "object") {
components.push(component);
}
};
return app;
}();
在這個重寫後的應用程式單例中,首先也是像前面例子中一樣定義了私有變量。主要的不同之處在于命名變量的app的建立過程,因為它必須是BaseComponent的執行個體。這個執行個體實際上是application對象的局部變量版。此後,我們又為app對象添加了能夠通路私有變量的方法。最後一步是傳回app對象,結果仍然是将它指派給全局變量application。
備注: 摘取自《JAVASCRIPT進階程式設計:第3版》