單體模式的概述:
單體是一個只能被實例化一次而且能夠經過一個衆所周知的訪問點訪問的類。
單體是一個用來劃分命名空間並將一批相關方法和屬性組織在一塊兒的對象。若是它能夠被實例化,那麼他只能被實例化一次。 javascript
單體對象的區分;
1.並不是全部的對象字面量都是單體。若是他只是用來模仿關聯數組或容納數據的話,那就不是單體。
2.若是用來組織一批相關方法和屬性話。那就多是單體。
1.單體的基本結構
最簡單的單體實際上就是一個對象字面量,它把一批有必定關聯的方法和屬性組織在一塊兒
var Singleton = {
attribute1 : true,
attribute2 : 10,
method1:function(){ java
},
method2:function(){ 程序員
}
} 編程
類分析:
1.這個單體對象被修改。能夠爲對象添加新成員。
2.可使用delete運算符刪除其現有成員。
3.面向對象設計的原則:類能夠被擴展,可是不能 被修改。 數組
5.2劃分命名空間
單體對象有兩部分組成:
包含着方法和屬性成員的對象自身。以及用來訪問它的變量。(這個變量一般是全局性的,以便在網頁上任何地方都能直接訪問到它所指向的單體對象。) 這是單體模式的一個要點。
命名空間是可靠的javascript編程的一個重要工具。
爲了不無心中改下變量,最好的解決方法之一是用單體對象將代碼組織在命名空間之中。
var Mynamespace = {
findProduct : function(id){ 閉包
}
} 函數
分析:
1.如今findProduct函數是一個Mynamespace的中一個方法,不會被全局命名空間中聲明的任何新變量改寫。
2.用命名空間把相似的方法組織在一塊兒。有助於加強代碼的文檔性。
命名空間進一步分割。
各類javascript代碼,都有可能出如今全局命名空間中。
爲了不衝突,能夠定義一個用來包含本身的全部代碼的全局對象:
var GiantCorp = {};
2.而後能夠分悶別類地把本身的代碼和數據組織到這個全局對象中的各類對象中:
GiantCorp.Common = { 工具
} 網站
5.3 用做特定網頁專用代碼的包裝器的單體
場景描述:
在有不少網頁網頁的網站中,有些javascript代碼是全部的網頁都要用到的,因此他們被存放在獨立的文件中,有些代碼是某個網頁專用的。不會被用到其餘地方。
建議:最後把這兩種代碼分別包裝在本身的單體對象中。
包裝特定網頁的專用代碼的單體的骨架:
Namespace.PageName = {
CONSTANT_1:true,
CONSTANT_2:10,
method1:function(){ this
},
method2:function(){
}
init:function(){
}
}
5.4擁有私有成員的單體
5.4.1使用下劃線表示法
1.在單體對象內建立私有成員最簡單,。最直接了當的辦法是使用下劃線表示法。
2.在單體對象中使用下劃線表示法是一種告誡其餘程序員不要直接訪問特定成員的簡明方法
GiantCorp.DataParser = {
_stripWhitespace :function(str){
return str.replace(/\s+/,'');
},
_stringSplit:function(str,delimiter){
return str.split(delimiter)
},
string:function(str,delimiter,stripws){
if(stripws);
str = this.__stripWhitespace(str);
var outputArray = this._stringSplit(str,delimiter);
return outputArray;
}
}
5.4.2 使用閉包
在單體對象中建立私有成員的第二種方法須要藉助閉包,這個和第3章中建立真正的私有成員的作法很是類似。可是有一個(重要的區別)
1.以前的作法是吧變量和函數定義在構造函數體內,讓他變成私有成員。
2.構造函數體內定義了全部的特權方法並用this關鍵字使其可被外界訪問。
3.每次生成一個該類的實例時,全部的聲明的構造函數內的方法和屬性都會再次建立一次。
單體模式使用閉包:
1.單體只會被實例化一次。不用擔憂本身在構造函數中聲明瞭多少成員。
2.每一個屬性和方法都會被建立一次。全部能夠把他們聲明在構造函數內部
mynamespace.singleton = {};
建立一個定義以後當即執行的函數建立單體:
mynamespace.singleton = function{
return{};
}();
類的做用和分析:
1.第二個例子中並無把一個函數複製給mynamespace.singleton。
2.匿名函數返回類一個對象,而賦給mynamespace.singletion變量的正是這個對象。
3.爲了理解執行這個匿名函數,只需在其定義的最後那個大括號後面放上一堆圓括號便可。
5.4.3兩種技術的比較
看dataparser例子,看看如何在其實現中使用真正的私有成員,不在是經過下劃線爲每一個私有方法。
giantcorp.dataparser = (function(){
//私有屬性
var while = /\s+/;
//私有方法
function stripwhitespace(str){
return str.replace(while,'');
}
function stringsplit(str,delimiter){
return str.split(delimiter);
}
return {
stringtoarray:function(str,delimiter,stripws){
if(stripws){
str = stripwhitespace(str);
}
}
var outputArray = stringSplit(str,delimiter);
retrun outputArray;
}
})();
類分析:
1.如今這些私有方法和屬性能夠直接用其名稱訪問,沒必要在其前面加上「this.」或「dataparser.」 這些前綴只用於訪問單體對象的公有成員。
這個模式與使用下劃線表示法的模式比較的幾點優點
1.把私有成員放到閉包中能夠確保其不會在單體對象以外被使用。
2.能夠自由的改變對象的實現細節。不會殃及別人的代碼。
3.這種方法對數據進行保護和封裝。
單體模式帶來的好處:
1.在使用這種模式時,你能夠享受到真正的私有成員帶來的全部好處。
2.單體類只會被實例化一次。
3.單體模式是javascript種最流行、應有最普遍的模式之一。
5.5惰性實例化:
前面所講的單體模式的各類方法實現方式有一個共同點:
1.單體對象都是在腳本加載時被建立出來
2.對於資源密集型的或配置開銷甚大的單體,在須要用到的才建立對象。這個技術被稱爲懶惰加載。
3.做爲命名空間。特定網頁專用的代碼包裝器或者組織相關實用的方法仍是當即加載。
4.懶惰加載單體的特別之處。訪問他們必須藉助於一個靜態。
調用方式:Singleton.geninstance().methodname()而不是這樣調用:singleton.methodname().
5.getinstace方法會檢查該單體是否已經被實例化。若是沒有。那麼它將建立並返回其實例。已經實例化就會返回如今的實例。
6. 把普通的單體轉化爲惰性加載單體:
mynamespace.singleton = (function(){
var privateAttribute1 = false;
var privateAttribute2 = [1,2,3];
function privateMethod1(){
}
function privateMethod2(args){
}
return {
publicAttribute1 : true,
publicAttribute2 : 10,
publicMethod1 : function(){
},
publicMethod2 : function(){
}
}
})()
轉化第一步:把單體的全部代碼移到一個名爲constructor方法中:
mynamespace.singleton = (function(){
function constructor(){
var privateAttribute1 = false;
var privateAttribute2 = [1,2,3];
function privateMethod1(){
}
function privateMethod2(args){
}
return {
publicAttribute1 : true,
publicAttribute2 : 10,
publicMethod1 : function(){
},
publicMethod2 : function(){
}
}
}
})()
類分析:
1. 這個方法不能從閉包外部訪問,因此咱們能夠全權控制器調用時機。
2.公有方法getInstances是用來控制實現這種控制。
3.getInstace要變成公有方法,須要放到一個對象字面量返回對象便可;
examples:
mynamaespace.singleton = (function(){
function constructor (){
}
return {
getinstace:{
}
}
})()
編寫用於控制單體類的實例化時機的代碼,須要中兩件事:
1.必須知道該類是否被實例化過。
2.若是該類已經被實例化過。那麼他須要掌握其實力的狀況,以便能返回這個實例
3.辦這兩件事須要用一個私有屬性的已有的私有方法constructor
mynamespace.singleton = (function(){
var uniqueInstace;
function constructor(){}
return {
getInstace : function(){
if(uniqueinstace){
uniqueInstace = constructor();
}
return uniqueInstace;
}
}
})()
調用方式:mynamespace.singleton.getinstace().publicmethod1();
命名空間太長簡化分: var mns = mynamespace.singleton;
5.6分支
5.8單體模式的適應場合 1。從未代碼的提供命名空間和加強模塊的角度來講,應該儘可能多使用單體模式。 2.