# 設計模式 -- 單例模式
* [什么是單例模式](http://www.hmoore.net/cyyspring/more/1317334#_1)
* [使用場景](http://www.hmoore.net/cyyspring/more/1317334#_12)
* [優缺點](http://www.hmoore.net/cyyspring/more/1317334#_18)
* [es5 實現單例模式](http://www.hmoore.net/cyyspring/more/1317334#es5__29)
* [透明的單例模式](http://www.hmoore.net/cyyspring/more/1317334#_96)
* [使用代理模式創建](http://www.hmoore.net/cyyspring/more/1317334#_147)
> # 什么是單例模式
* [推薦參考看的文章](https://segmentfault.com/a/1190000012842251#articleHeader5)
~~~
1.保證一個類僅有一個實例,并提供一個訪問它的全局訪問點
'意圖:' 保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
'主要解決:'一個全局使用的類頻繁地創建與銷毀。
'何時使用:'當您想控制實例數目,節省系統資源的時候。
'如何解決:'判斷系統是否已經有這個單例,如果有則返回,如果沒有則創建。
2.因此要實現一個單例模式無非是使用一個變量來標記當前是否已經為某個類創建
了對象,如果創建則在下一次直接獲取之前返回創建的實例
~~~
> ##### 使用場景
~~~
1.線程池、全局緩存、瀏覽器中的window對象 舉個例子:當點擊頁面的登錄案例,
會彈出登錄彈窗,這個彈窗無論點擊多少次只能被創建一次,那么這個彈窗就可以
用單例模式創建
~~~
> ##### 優缺點
* 優點
~~~
1、在內存里只有一個實例,減少了內存的開銷,尤其是頻繁的創建和銷毀實例
2、避免對資源的多重占用
~~~
* 缺點
* [單一職責](https://blog.csdn.net/zhengzhb/article/details/7278174/)
~~~
1.與單一職責原則沖突,一個類應該只關心內部邏輯,而不關心外面怎么樣來實例化
~~~
> ##### es5 實現單例模式
~~~
1.下面的案例根據上面的分析想單例模式,首先需要一個可以用來標記是否已經創建實例的屬性,
下面案例用的是'instance '做的這件事,因此特意用的是類屬性來標記,并且對外提供可一個方法
用來'getInstance '也是靜態方法,用來做實例是否是第一次創建
2.通過下面案例的'a' 和'b' 打印的'name'都是'wang',也可以發現,實例只被創建了一次,也就是第一次
的'a',而'b'沒有在創建了實例還是用的'a'創建的實例
3.下面單例模式寫法的缺點:這個單例實現獲取對象的方式經常見于新手的寫法,這種方式獲取對象
雖然簡單,但是這種實現方式不透明。知道的人可以通過 Singleton.getInstance() 獲取對象,
不知道的需要研究代碼的實現,這樣不好。這與我們常見的用 new 關鍵字來獲取對象有出入,
實際意義不大。
~~~
~~~
var Singleton = function (name) {
this.name = name
}
// 靜態屬性(類屬性)
Singleton.instance = null
Singleton.prototype.getName = function () {
console.log(this.name)
}
// 靜態
Singleton.getInstance = function (name) {
if(!Singleton.instance){
Singleton.instance = new Singleton(name)
}
return Singleton.instance
}
var a = Singleton.getInstance('wang')
var b = Singleton.getInstance('Yi')
console.log(a.name) // wang
console.log(b.name) // wang
console.log(a === b ) // true
~~~
* 第二種用getInstance 方法用閉包的方式
~~~
var Singleton = function (name) {
this.name = name
}
Singleton.prototype.getName = function () {
console.log(this.name)
}
// 靜態
Singleton.getInstance =( function () {
var instance = null
return function (name) {
if(!instance){
instance = new Singleton(name)
}
return instance
}
})()
var a = Singleton.getInstance('wang')
var b = Singleton.getInstance('Yi')
console.log(a.name) // wang
console.log(b.name) // wang
console.log(a === b ) // true
~~~
> ##### 透明的單例模式
~~~
1.透明的單例模式是為了可以向正常創建實例一樣通過'new'的形式使用
2.下面案例首先整體思路和單例模式還是一樣,需要一個值用來記錄創建
的實例,如果已經創建則用記錄的實例,如果沒有創建則創建一個新的實例
3.但為了實現,現在的構想,想通過new來創建而不是像上個案例通過暴露
出來的類方法,要做的就是需要將構造函數暴露出來才能new成功,這里有個
小知識點'構造函數中如果return 是一個對象,則返回的是return 后面的對象'
4.下面的案例看似復雜,實際就做了一件事,當對象第一次創建的時候調用他的
初始化方法,初始化方法是用來生成div標簽的,并且返回當前實例且記錄下來當
再一次使用的時候如果有則返回記錄的實例
5.通過下面創建的'a' 和 'b',創建a的時候頁面會生成一個div的dom節點并且里面是sven1,
但當創建'b'的時候不會有任何反應在頁面上因為,a 和 b是同一個實例,且只有創建新的
實例的時候才會在構造函數內自動執行init,也變相說明'b'沒有創建實例,當通過b調用
init方法的時候頁面會生成一個div的dom節點并且里面是sven1,因為'b'不創建實例,因此
用的是'a'創建時候初始化賦的值
6.缺點代碼不易讀不易改
~~~
~~~
var CreateDiv = (function (html) {
var instance
// 實際創建的構造函數,也就是最后實際
// 生成的實例的構造函數
var CreateDiv = function (html) {
if(instance){
return instance
}
this.html = html
this.init()
return instance = this // 返回第一次創建的實例并且通過instance記錄
};
// 初始化創建方法,會創建div標簽
CreateDiv.prototype.init = function () {
var div = document.createElement('div')
div.innerHTML = this.html
document.body.appendChild(div)
}
return CreateDiv
})()
var a = new CreateDiv('sven1')
var b = new CreateDiv('sven2')
b.init()
~~~
> ##### 使用代理模式創建
~~~
1.代理模式:自己不去做,委托中間人做
2.Person是一個普通類,通過new Person可以創建一個對象
3.用代理模式創建CreateSinglePerson方法,通過new CreateSinglePerson可以創建一個單例
4.這個寫法相當于剛才兩種已經不錯了,既可以讀懂,又是通過new創建的
~~~
~~~
function Person(name) {
this.name = name;
}
Person.prototype.getName = function () {
console.log(this.name);
};
var CreateSinglePerson = (function (name) {
var instance;
return function () {
if (!instance) {
instance = new Person(name);
}
return instance;
};
})();
var a = new CreateSinglePerson('a');
var b = new CreateSinglePerson('b');
console.log(a === b); // true
var c = new Person('c');
var d = new Person('d');
console.log(c === d); // false
~~~
- 視覺規范
- 色彩
- 文字
- 偏移
- 圖標
- 列表組件
- 表單組件
- 詳情組件
- 其他組件
- 研發規范
- 編碼規范
- 函數式編程
- 純函數
- 柯里化
- 函數組合
- 函子
- 面向對象編程
- 設計原則
- 單一職責原則
- 里氏替換原則
- 依賴倒置原則
- 接口隔離原則
- 開閉原則
- 迪米特原則
- 組合復用原則
- 設計模式
- 創建型模式
- 工廠模式
- 簡單工廠
- 工廠方法
- 抽象工廠
- 單例模式
- 建造者模式
- 原型模式
- 結構型模式
- 適配器模式
- 橋接模式
- 過濾器模式
- 組合模式
- 裝飾器模式
- 外觀模式
- 享元模式
- 代理模式
- 行為型模式
- 責任鏈模式
- 命令模式
- 解釋器模式
- 迭代器模式
- 中介者模式
- 備忘錄模式
- 觀察者模式
- 狀態模式
- 策略模式
- 模板模式
- 訪問者模式
- 組件設計規范
- 組件文檔編寫規范
- 版本管理規范