javascript单例模式与策略模式实例详解
作者:flying_huixia
这篇文章主要介绍了javascript单例模式与策略模式,结合实例形式详细分析了javascript单例模式与策略模式基本概念、功能、实现技巧与相关注意事项,需要的朋友可以参考下
一、单例模式
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) } } }
运行页面: