設計模式-誰沒碰見過幾個單例模式(一)

1、什麼是單例模式

單例模式的定義是,保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。javascript

有一些對象,好比線程池/全局緩存/瀏覽器中的 window 對象等等,咱們只須要一個實例。下面將根據實際場景進行介紹。html

2、實際場景

1. 登陸浮窗

當咱們單擊登陸按鈕時,頁面中會出現一個登陸的浮窗,而這個登陸浮窗是惟一的,不管單擊多少次登陸按鈕,這個浮窗都只會被建立一次,那麼這個登陸浮窗就適合用單例模式來建立。java

1.1 傳統作法

傳統作法在頁面加載完成時,就建立好登陸浮窗,當用戶點擊登陸按鈕時,顯示登陸浮窗,實現代碼以下:git

<!DOCTYPE html>
<html>
<head>
	<title></title>
</head>
<body>
  
	<button id="loginBtn">登陸</button>
	<script type="text/javascript" src="index.js">
		
	</script></body></html>
複製代碼
var loginLayer = (() => {
	let div = document.createElement('div')
	div.innerHTML = '我是登陸彈窗'
	div.style.display = 'none'

	document.body.appendChild(div)

	return div
})()

document.getElementById('loginBtn').onclick = () => {
	loginLayer.style.display = 'block'
}

複製代碼

源碼地址github

上述代碼有如下缺點:web

  1. 在無需登陸的狀況下,也會新增登陸浮窗的 DOM 節點,浪費性能。

如今優化一下,將代碼改成,在用戶點擊登陸按鈕後,才新增登陸浮窗的 DOM 節點。設計模式

代碼以下:瀏覽器

var createLoginLayer = () => {
	let div = document.createElement('div')
	div.innerHTML = '我是登陸彈窗'
	div.style.display = 'none'

	document.body.appendChild(div)

	return div
}

document.getElementById('loginBtn').onclick = () => {
	const loginLayer = createLoginLayer()
	loginLayer.style.display = 'block'
}

複製代碼

源碼地址緩存

上述代碼也存在缺陷,具體以下:markdown

  1. 每次點擊登陸按鈕,都會建立一個登陸浮窗,頻繁的建立 DOM 節點更加浪費性能。

實際上,咱們只須要建立一次登陸浮窗。

1.2 單例模式

經過單例模式,重構上述代碼。

const createLoginLayer = () => {
	const div = document.createElement('div')
	div.innerHTML = '我是登陸彈窗'
	div.style.display = 'none'
	console.log(123)

	document.body.appendChild(div)
	return div
}

const createSingle = (function () {
	var instance = {}
	return function (fn) {
		if (!instance[fn.name]) {
			instance[fn.name] = fn.apply(this, arguments)
		}
		return instance[fn.name]
	}
})()

const createIframe = function () {
	const iframe = document.createElement('iframe')
	document.body.appendChild(iframe)
	iframe.style.display = 'none'
	return iframe
}

const createSingleLoginLayer = createSingle(createLoginLayer)
const createSingleIframe = createSingle(createIframe)

document.getElementById('loginBtn').onclick = () => {
	const loginLayer = createSingleLoginLayer
	const iframe = createSingleIframe
	loginLayer.style.display = 'block'
	iframe.style.display = 'block'
}

複製代碼

源碼地址

通過重構,代碼作了如下優化:

  1. 將建立實例對象 createLoginLayer / createIframe 的職責和管理單例對象 createSingle 的職責分離,符合單一職責原則;
  2. 經過閉包存儲實例,並進行判斷,無論點擊登陸按鈕多少次,只建立一個登陸浮窗實例
  3. 易於擴展,當下次須要建立頁面中惟一的 iframe / script 等其餘標籤時,能夠直接複用該邏輯。

3、總結

單例模式是一種簡單但很是實用的模式,特別是惰性單例技術,在合適的時候才建立對象,而且只建立惟一的一個。更奇妙的是,建立對象和管理單例的職責被分佈在兩個不一樣的方法中,這兩個方法組合起來才具備單例模式的威力。


· 往期精彩 ·

【設計模式-誰沒碰見過幾個單例模式(一)】

【設計模式-什麼是快樂星球,什麼是策略模式(二)】

【設計模式-原來這就是代理模式(三)】

【設計模式-簡單易懂的觀察者模式(四)】

【設計模式-不會吧,不會還有人不知道裝飾器模式吧(五)】

相關文章
相關標籤/搜索