iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 1
1
Modern Web

JS Design Pattern 系列 第 1

JS Design Pattern Day01-單例模式 Singleton

  • 分享至 

  • xImage
  •  

嗨大家好,這系列主題都是從一本叫做 "JavaScript設計模式與開發實踐" 這本書範例練習來的,裡面講了十幾種設計模式以及一些哩哩叩叩的東西,反正就盡量寫完30篇。

今天就開始寫第一種模式:單例模式Singleton。

首先,單例模式的定義:保證一個類別僅有一個實例,並提供一個存取它的全域存取點,就網頁實際應用來說最常見大概就是建立一個元素然後需要被重複共用,像是loading page、警告視窗或是單頁網頁中常用的背景,或是系統中唯一的物件像是thread pool、特定的queue之類的。
舉個例子,現在要做一個簡單的登入頁面,點擊‘登入’按鈕之後彈出一個登入視窗。那大概可以這樣做:

//產生一個登入按鈕
var $button = (function() {
	return $('<button>').text('登入').appendTo('body');
})();

//產生一個登入畫面
var $loginLayer = (function() {
	var $layer = $('<div>').text('我是登入畫面').appendTo('body');
	$layer.hide();
	return $layer;
})();

//綁定按鈕事件
$button.click(showLayer);

//顯示登入畫面 
function showLayer() {
	$loginLayer.show();
}

這樣寫廣義來說就有點單例概念了,登入頁面不會因為多次點擊登入按鈕而重複的被產生,但是這樣寫有個缺點:還沒點擊登入按鈕登入畫面就被建立好了。可能有些人只是想瀏覽沒有要登入,因此多浪費一些資源。
所以改寫一下:點擊按鈕才開始製作,並且利用全域變數來判斷:

var $button = (function() {
	return $('<button>').text('登入').appendTo('body');
})();

var $loginLayer;

function createLayer() {
	if ($loginLayer) {
		return $loginLayer;
	} else {
		var $layer = $('<div>').text('我是登入畫面').appendTo('body');
		$layer.hide();
		return $layer;
	}
}

function showLayer() {
	$loginLayer = createLayer();
	$loginLayer.show();
}
$button.click(showLayer);

這樣寫還是有些小缺點:
1.違反單一職責原則,建立和管理都在同一個function裡(createLayer)
2.如果要製造其他物件的獨體,除了製作div那段之外其他幾乎都要全部複製一次
所以最後再改寫一下,做一個通用的單例模式:
首先利用getSingle函式來做單例判斷的行為,getSingle內部可以先用比較簡單的寫法

function getSingle(fn) {
	var singleItem;
	return function() {
		return singleItem || (singleItem = fn.apply(this));
	}
}

將單例實體的判斷與製作都交給這個function,因此可以帶入任何製作的function,再來我們將製作登入介面function準備好,這個function只管製作不用管是否單例

function createLayer(text) {
	var $layer = $('<div>').text('我是登入畫面').appendTo('body');
	$layer.hide();
	return $layer;
}

最後就是將製作登入畫面的createLayer丟入getSingle得到一個單例物件,就可以來控制這個物件了

var createSingleLoginLayer = getSingle(createLayer);

function showLayer() {
	createSingleLoginLayer().show();
}

最後完整的code:

var $button = (function() {
	return $('<button>').text('登入').appendTo('body');
})();

function getSingle(fn) {
	var singleItem;
	var argTmp = [].slice.call(arguments);
	var newArg = (function() {
		argTmp.shift();
		return argTmp;
	})();
	return function() {
		return singleItem || (singleItem = fn.apply(this, newArg));
	}
}

function createLayer(text) {
	var $layer = $('<div>').text(text).appendTo('body');
	$layer.hide();
	return $layer;
}

var createSingleLoginLayer = getSingle(createLayer,'我是登入畫面');

function showLayer() {
	createSingleLoginLayer().show();
}
$button.click(showLayer);

好以上就是單例模式啦,其實getSingle這樣的寫法也有點代理模式的感覺,之後也會練習到(如果我有寫到那天的話)!


下一篇
JS Design Pattern Day02-策略模式 Strategy
系列文
JS Design Pattern 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

3
糜糜卯卯
iT邦新手 5 級 ‧ 2019-01-22 08:35:37

看了大大的文章,我也去買了這本書,不過書字多又小(一下子就會睡著)
還是看大大的文章簡潔

以下分享給其他跟我一樣不知道怎麼跑範例的初學者

這本書的範例在 http://www.ituring.com.cn/book/1632 右邊中間的「隨書下載」
(不用登入就能下載了)

抓下來之後也不知道怎麼執行程式
google了一下之後,原來是有用到jQuery '$'

<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>

<script type="text/javascript">
    // 把大大的code,或書裡的範例放這邊
</script>

</body>
</html>

註:用vs code的live server跑大大的範例,還蠻方便的~

我要留言

立即登入留言