【2021.07】前端实现的三种基本设计模式

前言

前段时间找工作,在一次笔试过程中碰到过手写实现发布订阅者模式,后来回来总结了这三种设计模式的前端实现和应用。

提示:如有不对,请多多指教



一、单例模式

定义:1 、只有一个实例 2 、可以全局的访问
主要解决:一个全局使用的类 频繁的创建和销毁
何时使用:想控制实例的数量 节省系统化资源的时候
如何实现:判断系统是否已经有这个单例 如果有则返回 没有就创建
单例模式优点:内存中只有一个实例 ,减少内存的开销,尤其是频繁的创建和销毁实例 (比如首页页面的缓存)
使用场景:1、全局的缓存 2 弹窗

ES5实现单例模式
需求 实现一个登陆的弹窗

// 1、页面加载完成的时候已经创建好这个弹窗,一开始弹窗是隐藏的状态,弹窗出现
// 缺点:资源浪费
var loginLayer = (function(){
	var div = document.createElement('div')
	div.innerHTML = '我是登录的弹窗'
	div.style.display = 'none'
	document.body.appendChild(div)
	return div
})()
document.getElementById('button').onclik = function (){
	loginLayer.style.display = 'block'
}
// 2、点击创建
// 缺点:频繁创建和销毁

// 3、单例模式
// 判断系统是否已经有这个单例模式 如果有则返回 没有则创建
// 有一个标记在内存中做一个标记,不能被销毁,使用闭包实现
var loginLayer = (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').onclik = function (){
	var loginLayer = loginLayer()
	loginLayer.style.display = 'block'
}

// 单一职责思想进行改进单例:
//单例职责
var getSingle = function(fn){
	var result
	return function(){
		return result || (result = fn.apply(this,arguments))
	}
}
//创建登录框的职责
var loginLayer = function(){
	var div = document.createElement('div')
	div.innerHTML = '我是登录的弹窗'
	div.style.display = 'none'
	document.body.appendChild(div)
	return div
}
var creatSingleLogin = getSingle (loginLayer)
document.getElementById('button').onclik = function (){
	var loginLayer = creatSingleLogin()
	loginLayer.style.display = 'block'
}

ES6实现单例模式
1、无类的语言
2、Class类可以看做是es5构造函数的语法糖

// (1)、 es5构造函数:方法直接定义在prototype上
function person(name,sex){
	this.name = name
	this.sex = sex
}
person.prototype.say = function(){
	conosole.log(‘shazi’)
}
let person1  = new person(‘星空’,’男’)

// (2)、Es6实现:使用class类,class里面的方法实际也是定义在prototype
class person{
//constructor方法在实际开发过程中更多是做初始化的操作
	constructor(name,sex){
		this.name = name
		this.sex = sex
	}
	say(){
		conosole.log(‘shazi’)
	}
}
Let person1  = new person(‘星空’,’男’)

// (3)、Es6实现单例模式:静态方法static定义的方法只能被类本身调用,不能被实例调用
class person{
	//constructor方法在实际开发过程中更多是做初始化的操作
	constructor(name,sex){
		this.name = name
		this.sex = sex
	}
	static Say(name,sex){
		if(!this.instance){
			this.instance = new person(name,sex)
		}
		return this.instance
	}
}
Let person1  = person.Say(‘星空’,’男’)
Let person2  = person.Say(‘星空’,’男’)

二、策略模式

定义一系列的算法 把他们封装起来 并且他们之间可以相互替换
核心:将算法的使用和算法的实现分离开来

1、函数也是对象,策略模式封装算法

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

2、表单验证

常规写法

<form action=”xxx.com” method=”post” id=”registerForm”>
	请输入用户名:<input type=”text” name=”username”>
	请输入密码:<input type=”passwodrd” name=”passwodrd”>
	请输入电话号码:<input type=”text” name=”phonenumber”>
	<button>提交</button>
</form>
var registerFrom = document.getElementById(‘registerForm’)
registerFrom .onsubmit = function(){
	if(!registerFrom .username.value == ‘’){
		alert(‘用户名不能为空’)
		return false
	}
	if(!registerFrom .passwodrd.value.length < 6){
		alert(‘密码长度不能小于6)
		return false
	}
	if(!/^1[3|5|8][0-9]{9}$/.test(registerFrom .username.value)){
		alert(‘手机号码格式不正确’)
		return false
	}
}

运用策略模式 ,封装表单验证(实现分成三部分:策略对象 一系列算法 一系列业务逻辑)

// 策略对象
var strategise = {
	isNonEmpty:function(value,errorMsg){
		if(value == ‘’){
			return errorMsg
		}
	}
	minLength:function(value,length,errorMsg){
		if(value.length < 6){
			return errorMsg
		}
	}
	isMobile:function(value,errorMsg){
		if(!/^1[3|5|8][0-9]{9}$/.test(value)){
			return errorMsg
		}
	}
}

//  一系列业务逻辑 (假设存在验证类 Validator new Validator())
var registerFrom = document.getElementById('registerForm')
var validateFun = function(){
	var validator = new Validator()
	//添加验证规则
	validator.add(registerFrom.username,'isNonEmpty','用户名不能为空')
	validator.add(registerFrom.password,'minLength','密码长度不能小于6')
	validator.add(registerFrom.phonenumber,'isMobile','手机号码格式不正确')
	//开启验证
	var errorMsg = validator.start()
	return errorMsg
}
registerFrom.onsubmit = function (){
	var errorMsg = validateFun()
	if(errorMsg ){
		alert(errorMsg )
		return false
	}
}

// 一系列算法(封装策略类 构造函数  class)**
var validator = function (){
	//保存验证规则的数组
	this.cache = []
}
validator.prototype.add = function (dom, rule, errorMsg){
	var ary = rule.aplit(:)
	this.cache.push(function(){
		var strategy = ary.shift()//用户选择的验证规则
		ary.unshift(dom.value)
		ary.push(errorMsg)
		return strategies[strategy].apply(dom,ary)
		//return strategies[strategy](...ary)   //ary数组作为参数传递
	})
}
validator.prototype.start= function (){
	for(var i=0,vaFunc;vaFunc=this.cache[i++]){
			var msg = vaFunc()
		if(msg){
			return msg
		}
	}
}

三、发布订阅者模式

实现思路:
1、首先要想好谁是发布者(比如谁是卖家)
2、然后给发布者添加一个缓存列表,用于存放回调函数来通知订阅者(比如买家收藏了卖 家的店铺,卖家拥有收藏了该店铺的一个列表名单)
3、最后就是发布消息,发布者遍历这个缓存列表,依次触发里面存放的订阅者回调函数

var Event = (function(){
	var list ={},//缓存列表
	listen,//订阅者
	trigger,//发布者
	remove;//取消订阅
	listen = function(key,fn){
		if(!list[key]){
			list[key] = []
		}
		list[key].push(fn)
	}
	trigger = function(){
		//对应的key取出来,arguments伪数组,接收传入函数的所有参数
		var key = Array.prototype.shift.call(arguments)//取出第一个参数
		var fns = list[key]
		if(!fns || fns.length == 0){
			return
		}
		for(var i=0;fn;fn=fns[i++]){//发布给订阅者
			fn(...arguments)
		}
	}
	remove = function(key,fn){
		var fns = list[key]
		if(!fns){
			return false
		}
		if(!fn){
			//短路表达式、逻辑与 && 的运算方式,左边的值布尔转换后为true,那么返回	//右边的值
			fn && (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,trigger,remove}
})()

解决问题1:
实现低耦合,改进异步操作中的强耦合,比如登录成功后返回的信息在不能模块的应用

解决问题2:
vue实现跨组件之间的传值

发布者父组件:

name:'我师父组件'clickButton(){
	pubsub.trigger('item',this.name)
}

订阅者子组件:

msg:'',

let that = this
pubsub.listen('item',function(data){
	that.Msg = data
})

总结

一直觉得笨一点没关系,只要我保持学习,总有一天会飞起来。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值