js的设计模式

一、单例模式

1、定义

         只有一个实例,可以全局访问。

        主要解决:一个全局使用的类,频繁的创建和销毁

        何时使用:当想控制实例的数目,节省系统化资源的时候

        如何实现:判断系统是否已经有这个单例,如果有则返回,没有则创建

        单例模式优点:内存中只有一个实例,减少了内存的开销,尤其是频繁地创建和销毁实例,比如首页页面的缓存

2、案例

        实现一个登陆的弹窗

<html>
    <button id="button">登陆</button>
</html>
<script>
    //一般写法
    var createLoginLayer = (function(){
        var div
        return function(){
            if(!div){
                div=document.createElement('div')
                div.innerHTML = '我是登陆弹窗'
                div.style.display = 'none'
                document.body.appendChild(div)
            }
            return div
        }
    
    })()
    
    document.getElementById('button').onclick = function(){
        var loginLayer = createLoginLayer()
        loginLayer.style.display="block"
    }

    //单例模式的写法
    var getSingle = function(fn){
        var result
        return function(){
            return result || (result = fn.apply(this,arguments))
        }
    }
    var createLoginLayer = function(){
        var div=document.createElement('div')
            div.innerHTML = '我是登陆弹窗'
            div.style.display = 'none'
            document.body.appendChild(div)
        return div    
    }
    var createSingleLogin = getSingle (createLoginLayer )
    document.getElementById('button').onclick = function(){
        var loginLayer = createSingleLogin ()
        loginLayer.style.display="block"
    }
</script>

3、es6实现单例模式

...js
    class LyEDU{
        constructor(name,creator,products){
            this.name = name;
            this.creator = creator;
            this.products = products;
        }
        static getInstance(name,creator,products){
            if(!this.instance){
                this.instance = new LyEDU(name,creator,products)
            }
            return this.instance
        }
    }
    var LyCom = LyEDU.getInstance('1','2',['3','4'])
    var LyComCom = LyEDU.getInstance('5','6',['31','42'])
    console.log(LyCom === LyComCom) //true
...

二、策略模式

1、定义

        定义一系列的算法,把他们封装起来,并且他们之间可以相互替换

        核心:将算法的使用和算法的实现分离开来

2、案例

        绩效为S的人年终奖有4倍工资,绩效为A的人员年终奖有3倍工资,绩效为B的年终奖有2倍工资

var strategies = {
    "S":function(salary){
            return salary * 4
        },
    "A":function(salary){
            return salary * 3
        },
    "B":function(salary){
            return salary * 2
        },
}
var getBounds = function(level,salary){
    return strategies[level](salary)
}

console.log(getBounds('S',10000))

3、表单验证策略模式

一般代码:

...html
    <form action="XXX.com" method="post" id="registerForm">
        请输入用户名:<input type="text" name="username">
        请输入密码:<input type="password" name="password">
        请输入手机号码:<input type="text" name="phonenumber">
    </form>
...

...js
    var registerForm = document.getElementById('registerForm');
    registerForm.onsubmit = function(){
        if(registerForm.username.value == ''){
            alert('用户名不能为空')
            return false
        }
        if(registerForm.password.value.length < 6){
            alert('密码不能少于6位')
            return false
        }
        if(!/^1[3|5|7|8][0-9]{9}$/.test(registerForm.phonenumber.value)){
            alert('手机号码格式不正确')
            return false
        }
    }
...

策略模式的代码

var registerForm = document.getElementById('registerForm');
var strategies = {
    isNonEmpty: function(value,errorMsg){
        if(value ==''){
            return errorMsg
        }
    },
    minLength:function(value,length,errorMsg){
        if(value.length < length){
            return errorMsg
        }
    },
    isMobile:function(value,errorMsg){
        if(!/^1[3|8|5][0-9]{9}$/.test(value)){
            return errorMsg
        }
    }
}

//假设用户按照如下使用已经封装好的验证
var validateFun = function(){
    var validator = new Validator();
    validator.add(registerForm.username,'isNonEmpty','用户名不能为空')
    validator.add(registerForm.password,'mingLength:6','密码的长度不能小于6位')
    validator.add(registerForm.phonenumber,'isMobile','手机号码格式不正确')
    var errorMsg = validator.start()
    return errorMsg
}

registerForm.onsubmit = function(){
    var errorMsg = validateFun()
    if(errorMsg){
        alert(errorMsg)
        return false
    } 
}

// 参照假设的使用,封装验证类
var Validator = function(){
    this.cache = [];
}
Validator.prototype.add = function(dom,rule,errorMsg){
    var ary = rule.split(':')
    this.cache.push(function(){
        var stategy = ary.shift();
        ary.unshift(dome.value);
        ary.push(errorMsg)
        return strategies[stategy](...ary)
        //或者 return strategies[stategy].apply(dom,ary)
    })
}
Validator.prototype.start = function(){
    for(var i=0,vaFunc;vaFunc = this.cache[i++];){
        var msg = vaFunc();
        if(msg){
            return msg
        }
    }
}

三、发布订阅模式

1、含义

       发布订阅模式又称观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知

2、作用

        支持简单地广播通信,当对象状态发生改变,会自动通知已经订阅过的对象;

        可以应用在异步编程中,替代回调函数,可以订阅ajax之后的事件,只需要订阅自己需要的部分

        对象之间的松耦合,两个对象之间都互相不了解彼此,但是,不影响通信,当所有的订阅者出现的时候,发布的代码无需改变,同样发布的代码改变,只要之前约定的名称没有改变,也不影响订阅

        发布订阅者模式封装的代码如下:

				var Event = (function(){
					var list = {},
						listen,
						trigger,
						remove;
					listen=function(key,fn){
						if(!list[key]){
							list[key] = [];
						}
						list[key].push(fn);
					}
					trigger = function(){
						var key = Array.prototype.shift.call(arguments),
							fns = list[key]
						if(!fns || fns.length ==0){
							return false
						}
						for(var i=0,fn;fn=fns[i++]){
							fn.apply(this,arguments)
						}
					}
					remove = function(key,fn){
						var fns = list[key]
						if(!fns){
							return false
						}
						if(!fn){
							fns && (fns.length=0)
						}else{
							for(var i=fns.length-1;i >=0; i--){
								var _fn = fns[i]
								if(_fn === fn){
									fns.splice(i,1)
								}
							}
						}
					}
					return {
						listen:listen,
						trigger:trigger,
						remove:remove
					}
				})()

        实际代码使用如下

		var a =(function(){
			var count = 0;
			var button = document.getElementById('count')
			button.onclick = function(){
				Event.trigger('add',count++)
			}
		})()
		var b = (function(){
			var div = document.getElementById('showcount')
			Event.listen('add',function(count){
				div.innerHTML = count
			})
		})()

        3、缺点:创建订阅者需要消耗一定的时间和内存;虽然可以弱化对象之间的联系,如果过度使用的话,反而使代码不好理解、不好维护等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值