個人博客:github.com/ruizhengyun…javascript
在回答這個問題以前,先說下什麼是單例模式。 單例模式又叫單體模式,保證一個類僅有一個實例,這意味着第二次使用同一個類建立新對象時,獲得的是與第一次所建立的對象徹底相同,並提供全局訪問點。java
抓住關鍵詞 「惟一」 和 「全局訪問」 的對象,不經讓我想起全局對象。git
// 全局對象
var globaObj = {};
複製代碼
but,使用全局變量會有如下問題:es6
全局變量問題折中的應對方案:github
1.java 實現設計模式
// 0.0.3/Singleton.java
public class Singleton {
// 私有化構造函數,即外部不能使用 new Singleton(),外部不能使用new!!
private Singleton(){}
// 內部 new
private Singleton instance = null;
// 對外接口
public Singleton getInstance() {
if(instance === null) {
// 保證只會 new 一次
instance = new Singleton();
}
return instance;
}
//對象方法
public void show(name, pwd) {
System.out.printIn('展現');
}
}
public class SingletonDemo {
public static void main(String[] args) {
// 不合法
Singleton object = new Singleton();
// 正確使用,惟一可用可用對象
Singleton object = Singleton.getInstance();
object.show();
}
}
複製代碼
2.javascript 簡單實現 使用一個變量存儲類實例對象(值初始爲 null/undefined
)。進行類實例化時,判斷類實例對象是否存在,存在則返回該實例,不存在則建立類實例後返回。屢次調用類生成實例方法,返回同一個實例對象。閉包
// 0.0.3/Singleton.js
class Singleton {
constructor(name) {
this.name = name;
this.instance = null;
}
show() {
console.log(this.name);
}
}
Singleton.getInstance = function (name) {
if (this.instance) {
return this.instance;
}
return this.instance = new Singleton(name);
}
// 實例
// 只能使用靜態函數 getInstance,不能使用 new Singleton(),可是隻能文檔約束
let s1 = Singleton.getInstance('展現1');
s1.show();
let s2 = Singleton.getInstance('展現2');
s2.show();
console.log(s1 === s2); // true
let s3 = new Singleton('展現3');
s3.show();
let s4 = new Singleton('展現4');
s4.show();
console.log(s3 === s4); // false
複製代碼
上面 s1 === s2
爲 true
,而 s3 === s4
爲 false
,緣由在於 s1
和 s2
在堆內存中指向同一地址, 而 s3
和 s4
在堆內存開闢了兩套空間。ide
存在問題函數
Singleton.getInstance(...)
;3.javascript 透明實現 統一用 new
操做符獲取單例,而不是使用 Singleton.getInstance(...)
post
// 0.0.3/Singleton2.js
let Singleton = (function () {
let instance
return function (name) {
if (!instance) {
this.name = name;
return instance = this;
}
return instance;
}
})();
Singleton.prototype.show = function () {
console.log(this.name);
}
// 實例
let s3 = new Singleton('展現3');
s3.show();
let s4 = new Singleton('展現4');
s4.show();
console.log(s3 === s4); // true
複製代碼
透明版解決了簡單版不夠「透明」的問題,又可使用 new
操做符來建立實例對象,瞬間以爲天是藍色,這個顏色真美,看誰也都順眼了。
4.javascript 代理版
// 0.0.3/Singleton3.js
let SingletonProxy = (function () {
let instance
function main(name) {
if (!instance) {
return instance = new Singleton(name);
}
return instance;
}
return main
})();
let Singleton = function (name) {
this.name = name;
}
Singleton.prototype.show = function () {
console.log(this.name);
}
// 實例
const p1 = new SingletonProxy('代理1');
p1.show(); // 代理1
const p2 = new SingletonProxy('代理2');
p2.show(); // 代理1
console.log(p1 === p2); // true
複製代碼
將管理單例操做,與對象建立操做進行拆分,實現更小的粒度劃分,符合「單一職責原則」。
1.模態框(登陸框,信息提高框)
// 0.0.3/SingletonModal.js
class Modal {
constructor() {
this.display = 'hide';
}
show() {
if (this.display === 'show') {
console.log('不可重複展現');
return
}
this.display = 'show';
console.log('成功展現');
}
hide() {
if (this.display === 'hide') {
console.log('不可重複隱藏');
return
}
this.display = 'hide';
console.log('成功隱藏');
}
}
Modal.getInstance = (function () {
let instance = null
return function () {
if (instance === null) {
instance = new Modal();
}
return instance;
}
})();
// 實例
let m1 = Modal.getInstance();
let m2 = Modal.getInstance();
m1.show();
m2.show();
m1.hide();
m2.hide();
console.log(m1 === m2);
複製代碼
2.其餘
項目中引入第三方庫時,重複屢次加載庫文件時,全局只會實例化一個庫對象,如 jQuery,lodash,moment ...
, 其實它們的實現理念也是單例模式應用的一種:
// 引入代碼庫 libs(庫別名)
if (window.libs != null) {
return window.libs; // 直接返回
} else {
window.libs = '...'; // 初始化
}
複製代碼