一、單例模式
1、概念
保證一個類僅有一個實例,並提供一個訪問它的全局訪問點
2、單例模式的實現 -- 以創建div節點爲例
var createDiv = (function(){
var instance;
var createDiv = function(html){
if(instance){
return instance
}
this.html = html;
this.init();
return instance = this;
};
createDiv.prototype.init = function(){
var div = document.createElement('div');
div.innerHTML = this.html;
document.body.appendChild(div)
}
return createDiv;
})()
var a =new createDiv('one');
var b =new createDiv('two');
console.log(a===b); //true
上述例子有缺點:
(1)使用了匿名自執行函數,增加了函數複雜度
(2) createDiv函數做了兩件事情,一是創建對象,二是管理單例。違背了單一職責原則
改進--》使用代理實現
//代理模式--改進
//只負責創建div的一個類
var createDiv = function (html) {
this.html = html;
this.init();
};
createDiv.prototype.init = function () {
var div = document.createElement('div');
div.innerHTML = this.html;
document.body.appendChild(div)
}
//引入代理類
var proxySingle = (function(){
var instance;
return function(html){
if(!instance){
instance = new createDiv(html)
}
return instance
}
})();
var a = new proxySingle('one');
var b = new proxySingle('two');
console.log(a === b); //true
3、惰性單例(使用)
只在需要的時候才創建對象實例
聯繫登陸功能的需求,登陸的彈框只會出現一次,在點擊點擊登陸按鈕的時候出現
兩種實現
(1)在頁面加載完成時,創建好這個浮窗,浮窗一開始是隱藏狀態,當用戶點擊登錄的時候,它纔開始顯示。缺點:會白白浪費一些DOM節點。
(2)當用戶點擊登陸按鈕時纔開始創建浮窗:代碼如下:
var createLoginer = function(){
var login = document.createElement("div");
login.innerHTML='登錄浮窗';
login.style.display = 'none';
document.body.appendChild(login);
return login
}
//點擊登陸按鈕
btn.onclick = function(){
var loginer = createLoginer();
loginer.style.display = 'block';
}
現在惰性的目的達到了,但失去了單例的效果--》再次修改如下:
用一個變量判斷是否已經創建過登錄浮窗
//創建登陸浮窗
var createLoginer = function () {
var login = document.createElement("div");
login.innerHTML = '登錄浮窗';
login.style.display = 'none';
document.body.appendChild(login);
return login
}
var loginer;
var getSingle = function (fn) {
return function () {
console.log(this)
return loginer || (loginer = fn.apply(this))
}
}
//createSingleLoginer接下來作爲函數調用,所以getSingle得返回一個函數,並且這個函數得返回登錄浮窗
var createSingleLoginer = getSingle(createLoginer);
//點擊登陸按鈕
var btn = document.getElementById("btn");
btn.onclick = function () {
var loginer = createSingleLoginer();
loginer.style.display = 'block';
}
getSingle就是用來管理單例的
惰性單例:只有在合適的時候才創建對象,並只創建唯一的一個。把創建對象和管理單例的職責分佈在不同的方法中,組合起來才能發揮真正的單例模式的威力。
二、策略模式
1、概念:
定義一系列的算法,把他們一個個封裝起來,並且使他們可以相互替換
2、實例
發年終獎,按照等級和各自的基礎工資進行乘積運算
var strage = {
S:function(salary){
return salary*4
},
A:function(salary){
return salary*3
},
B:function(salary){
return salary*2
}
}
var calculateBounus = function(level,salary){
return strage[level](salary)
};
console.log(calculateBounus('S',2000)) //8000
console.log(calculateBounus('A',2000)) //6000
3、策略模式用來封裝算法,更廣義的使用,表單驗證登錄算法
把校驗方式封裝成策略對象
var validatorFunc = function () {
var validator = new Validator();
validator.add(loginForm.userName, "isEmpty", '用戶名不能爲空')
validator.add(loginForm.passWord, "minLength:6", '密碼長度不能少於6位')
validator.add(loginForm.phone, "phoneValidator", '手機號碼格式錯誤')
var errMsg = validator.start();
return errMsg
}
var loginForm = document.getElementById("login")
function login() {
var errMsg = validatorFunc();
if (errMsg) {
alert(errMsg);
return false; //阻止表單提交
}
}
var Validator = function () {
//緩存校驗規則
this.cache = [];
}
Validator.prototype.add = function (dom, rule, err) {
var ary = rule.split(':');
this.cache.push(function () {
var strategy = ary.shift();
ary.unshift(dom.value);
ary.push(err)
return loginStrage[strategy].apply(dom, ary)
})
}
Validator.prototype.start = function () {
for (var i = 0; i < this.cache.length; i++) {
var err = this.cache[i]()
if (err) {
alert(err)
}
}
}
運行頁面: