设计模式:一种书写代码的方式,为解决特定问题给出的简介而优化的解决方案
1. 单例模式
/*
单例模式
单:单一
例:实例
一个构造函数一生只能有一个实例,不管你new多少次,都是这一个实例
应用:自定义弹出层
结构:div 》 xxxx, 默认隐藏,在一定条件下显示
实现:每次都是一个div来回显示,只是内容不一样
*/
const Person = (function () {
function Person(name, age) {
this.name = name
this.age = age
}
let instance = null
return function singleTon(...args) {
if (!instance) {
instance = new Person(...args)
}
return instance
}
})()
const p1 = new Person('Jack', 20)
const p2 = new Person('Rose', 30)
console.log(p1, p2)
console.log(p1 === p2) // true
2. 观察者模式
/*
观察者模式:
+ 例子:监控
=> 我们坐在教室里就是被观察者
=> 监控后面的老师就是观察者
=> 当被观察者触发了一些条件的时候,观察者就会触发技能
+ 观察者模式:监控一个对象的状态,一旦状态发生变化,马上触发技能
=> 需要两个构造函数来实现
1. 创建被观察者
=> 属性,自己的状态
=> 队列,记录都有谁观察自己
=> 方法1,能设置自己的状态,当我需要改变的时候,触发这个方法改变状态
=> 方法2,添加观察者
=> 方法3,删除观察者
2. 创建观察者
=> 需要一个身份证明
=> 需要一个技能
*/
// 观察者构造函数
class Observer {
constructor(name, fn = () => {}) {
this.name = name
this.fn = fn
}
}
// 创建三个个观察者
const njzr = new Observer('年级主任', (state) => {
console.log('因为:' + state + '所以:告诉你的班主任')
})
const bzr = new Observer('班主任', (state) => {
console.log('因为:' + state + '所以:把你爸找来')
})
const xz = new Observer('校长', (state) => {
console.log('因为:' + state + '所以:骂你的班主任')
})
// console.log(bzr, xz)
// 被观察者构造函数
class Subject {
constructor(state) {
this.state = state // 记录自己的状态
this.observers = [] // 保存观察着我的人
}
// 设置自己的状态
setState(state) {
this.state = state
// 就需要把我的所有观察者的技能都触发
// 遍历this.observers 依次触发技能
this.observers.forEach(item => {
// 把每一个观察者的技能触发
// 告诉他我改变成了什么状态
item.fn(this.state)
})
}
// 添加观察者
addObserver(obs) {
this.observers = this.observers.filter(item => item !== obs)
this.observers.push(obs)
}
// 删除观察者
delObserver(obs) {
this.observers = this.observers.filter(item => item !== obs)
}
}
// 创建一个被观察者
const xiaoming = new Subject('学习')
xiaoming.addObserver(njzr)
xiaoming.addObserver(bzr)
xiaoming.addObserver(xz)
console.log(xiaoming)
const xiaohong = new Subject('学习')
xiaohong.addObserver(bzr)
xiaohong.addObserver(xz)
console.log(xiaohong)
3. 发布订阅模式
/*
发布订阅模式
+ 有一个对象,有人在一直看着他
+ 当这个对象发生改变的时候,第三方通知这个看着的人,触发技能
+ 例子:买书
1. 普通程序员买书
=> 去书店,问,没有
=> 回家
=> 过一会儿再去,问,没有,回家
=> 过一会儿再去,问,没有,回家
2. 发布订阅的程序员
=> 去书店买书,问,没有,留下一个联系方式给店员
=> 一旦有了书,就会接到电话
=> 触发技能去买书
+ 只需要一个构造函数
=> 创建一个第三方店员的身份
=> 我们的任务就是模拟一个addEventListener()
分析构造函数
+ 属性:任务队列
{
click:[fn1, fn2]
abc:[fn1, fn2, fn3]
}
+ 方法1:能向消息队列里面添加内容
+ 方法2:删除队列里面的内容
+ 方法3:触发消息队列
*/
// 第三方观察者类
class Observer {
constructor() {
this.message = {}
}
// 1. 向消息队列里面添加内容
on(type, fn) {
// type: 我拜托你看着的行为
// fn: 在行为发生后,你要做的事情
// 把这些记录在消息队列中
// 1. 判断行为是否被注册过
if (!this.message[type]) {
this.message[type] = []
}
this.message[type].push(fn)
}
// 2. 删除消息队列里面的内容
off(type, fn) {
// fn不存在,只有一个参数的情况
if (!fn) {
// 直接把这个事情取消掉
delete this.message[type]
return
}
// fn存在
if (!this.message[type]) return // 没订阅过什么都不做
// 订阅过
this.message[type] = this.message[type].filter(item => item !== fn)
}
// 3. 触发消息队列
trigger(type) {
if (!this.message[type]) return // 判断是否被订阅过
this.message[type].forEach(item => {
item()
})
}
}
// 创建一个观察者实例
const person1 = new Observer()
console.log(person1)
// 当你想拜托这个person1帮你观察一些内容的时候
// 要告诉他一个行为,当行为出现的时候,告诉他该干什么(订阅一个行为)
person1.on('高程3', handlerA)
person1.on('高程3', handlerB)
person1.on('犀牛书', handlerC)
person1.on('犀牛书', handlerD)
// 1. 我的朋友送给我了犀牛书,我的这个事情不用你管了(取消订阅)
// person1.off('犀牛书')
// 2. 犀牛书来了,只去办C,不用去办D了
// person1.off('犀牛书', handlerD)
// person1.off('你不知道的js', handlerE)
// person一旦触发a行为,就要把后面所有的时间都进行处理
person1.trigger('高程3')
function handlerA() {
console.log('handlerA')
}
function handlerB() {
console.log('handlerB')
}
function handlerC() {
console.log('handlerC')
}
function handlerD() {
console.log('handlerD')
}
4. 策略模式
/*
策略模式
+ 一个问题可以匹配多个解决方案,不一定要用到哪一个
+ 而且有可能随时还会继续添加多个方案
+ 例子:购物车结算
=> 我们有好多种折扣计算方式
=> 满 100 减 10
=> 满 200 减 25
=> 8折
1. 把我们的多种方案,以闭包的形式保存起来
+ 按照传递进来的折扣和价格计算最终的价格返回
2. 留下添加折扣方式和删除折扣方式的接口
+ 函数也是一个对象
+ 可以把函数名当做一个对象,向里面添加一些成员
*/
// 接受两个参数,1. 价格 2. 折扣种类
// 如果现在多了一种折扣方式,我们就需要改源代码,加一个else if判断
// 活动结束后,还要删除这个方式
// function calcPrice(price, type) {
// if (type === '100_10') {
// price -= 10
// } else if (type === '200_25') {
// price -= 25
// } else if (type === '80%') {
// price *= 0.8
// } else {
// console.log('没有这种折扣方式')
// }
// return price
// }
// const res = calcPrice(320, '100_10')
// console.log(res)
// 1. 暂时以闭包的形式把折扣方案保存下来
const calcPrice = (function () {
const sale = {
'100_10': function (price) {
return price -= 10
},
'200_25': function (price) {
return price -= 25
},
'80%': function (price) {
return price *= 0.8
}
}
function calcPrice(price, type) {
if (!sale[type]) return '没有这个折扣方案'
return sale[type](price)
}
// 把函数当做一个对象,向里面添加一些成员
calcPrice.add = function (type, fn) {
// 判断折扣方式是否存在
if (sale[type]) return '该折扣方式已经存在'
sale[type] = fn
return '添加成功'
}
// 删除成员
calcPrice.del = function (type) {
delete sale[type]
}
return calcPrice
})()
const res = calcPrice.add('100_50', price => price -= 50)
// console.log(res)
let result = calcPrice(320, '100_50')
console.log(result)