1.了解设计模式
+ 什么是设计模式?
=> 针对 特定问题, 给出的简洁而优化的处理方案
+ 一个设计模式 A
=> 只能解决 A 类型的问题
=> 针对 B 类型的问题, 设计模式 A 解决不了
+ 同一个问题, 再不同的位置, 是不一定能用同一种方案解决
+ 设计模式, 只在特定的情况, 特定的时期, 针对特定的问题使用
市场上常用的设计模式
+ 单例模式
+ 组合模式
+ 观察者模式
+ 适配器模式
+ 代理模式
+ 工厂模式
+ 构建模式
+ ...
我大概说一下前三种
2.单例模式
+ 单: 单一, 一个, 独个
+ 例: 实例(构造函数的实例化对象)
+ 让一个构造函数一辈子只有一个实例对象
=> 当你需要一个构造函数一生只能 new 出一个对象的时候
=> 就可以使用单例模式
单例模式的简单应用
+ 弹出层 alert() 比较丑, 用户体验极度不好
+ 好多网站会使用一个自己写的 div 盒子, 当作弹出层
+ 再自己写的过程中, 一个网站不可能只弹出一次
=> 不能每次弹出就创建一个 div
=> 每次弹出的都是之前创造好的那个 div, 只是文字改变了
+ 创造 div 并显示出来的构造函数
=> 如果不用单例模式, 每次 new 就是创造一个 div
=> 如果用了单例模式, 每次 new 都是用的第一次的 div, 只是改变文字内容
单例模式 核心代码
function Person() {
this.name = 'Jack'
}
var instance = null
function singleton() {
if (instance === null) {
instance = new Person()
}
return instance
}
var p1 = singleton()
var p2 = singleton()
console.log(p1 === p2)
应用会对核心代码进行升级
var Person = (function fn() {
function Person() {
this.name = 'Jack'
}
var instance = null
return function () {
return !instance ? instance = new Person() : instance
}
})()
var p1 = new Person()
var p2 = new Person()
console.log(p1)
console.log(p2)
console.log(p1 === p2)
3.组合模式
+ 组合模式:
=> 把我们若干这启动方式一样的构造函数放在一起
=> 准备一个总开关, 总开关一启动, 那么这些个构造函数就都启动了
实现组合模式:
+ 需要一个承载所有构造函数实例的数组
+ 需要一个方法, 向数组里面添加内容
+ 需要一个方法, 能把数组里面的所有内容启动了
应用场景
+ 轮播图:
class Play {
constructor () {}
init () {
console.log('开始玩游戏')
}
}
class Compose {
constructor () {
this.composeArr = []
}
add (instance) {
this.composeArr.push(instance)
}
init () {
console.log('总开关启动了')
this.composeArr.forEach(item => item.init())
}
}
var c = new Compose()
c.add(new Play())
c.init()
console.log('c')
}
4.观察者模式
+ 又称 发布/订阅 模式
+ 目前市场上的开发人员, 分成两派人员
=> 一派人, 认为 观察者 和 发布/订阅 是一个设计模式
=> 一派人, 认为 观察者 和 发布/订阅 是两个设计模式
+ 两派人到现在也没有定论
=> 目前还在互相想说服对方,因此分两个角度
=> 一个从 观察者 角度出发
=> 一个从 发布/订阅 角度出发
**观察者角度**
+ 目的:
=> 让 观察者 看着 被观察者, 只要数据改变了
=> 就让 观察者 做一些事情
+ 就像我们小时候的班主任一样
=> 班主任, 年级主任, 教务主任, 都有一个共同的能力叫做 请家长
=> 他们就是暗中观察我们的人, 一旦我们做的事情和他们想的不一样, 就回触发技能
=> 他们就是观察者, 当被观察者一旦出现变化, 立马触发他们的技能
+ 被观察者
=> 就是一个学生, 你的状态就应该是 好好学习
=> 一旦你的状态改变为 玩手机
=> 立马就会通知正在观察着你的人, 观察着你的人, 就会触发技能
// 1. 被观察者
class Student {
constructor () {
this.state = '好好学习'
this.observers = []
}
// 方法
// 1. 可以改变状态的方法
setState (value) {
this.state = value
// 状态一旦改变, 就要通知看着你的人
this.notify()
}
// 2. 获取自己的状态
getState () {
return this.state
}
// 3. 添加观察着
// 向 this.observers 里面追加一个看着这个同学的人
attach (observer) {
this.observers.push(observer)
}
// 4. 通知 this.observers 数组里面的每一个人, 状态改变了
notify () {
this.observers.forEach(item => item.qingjiazhang( this.state ))
}
}
// 2. 观察者
class Observer {
constructor (name) {
this.name = name
}
// 方法, 就是这些老师能触发的技能
qingjiazhang (state) {
console.log(`我是 ${ this.name }, 因为你 ${ state } 了, 我要请你家长来!`)
}
}
var xiaoming = new Student()
var banzhuren = new Observer('班主任')
xiaoming.attach(banzhuren)
xiaoming.setState('玩手机')
console.log(xiaoming)
**发布/订阅 角度**
+ 分成三个状态
=> 订阅
=> 取消订阅
=> 发布
+ js 里面由实际应用
=> addEventListener('click', fn)
=> 当 click 行为触发的时候, 就会执行 fn 函数
=> 还可以绑定多个事件处理函数
=> 当 click 行为触发的时候, 所有的事件处理函数 都会执行
+ 做的事情
=> 就是模仿 addEventListener 自己定一个事件监听
发布/订阅 需要的内容
1. 消息盒子 {}
=> click: [fn1, fn2, fn3]
=> mouseover: [fn4, fn5, fn6]
2. 订阅的方法
=> 向消息盒子里面添加内容
3. 取消订阅的方法
=> 把已经订阅的方法从消息盒子内部拿走
4. 发布事件的方法
=> 把消息盒子里面的对应的处理函数执行了
class Observer {
constructor () {
// 准备的消息盒子
this.message = {}
}
// 订阅的方法
on (type, fn) {
if (!this.message[type]) {
this.message[type] = []
}
this.message[type].push(fn)
}
// 取消订阅的方法
off (type, fn) {
if (!this.message[type]) return
this.message[type] = this.message[type].filter(item => item !== fn)
}
// 发布的方法
emit (type, ...arg) {
if (!this.message[type]) return
console.log(arg)
// 自己组装一个事件对象
var event = {
type: type,
// 参数
data: arg
}
// 调用每一个事件处理函数的时候, 都给你带上一个事件对象
this.message[type].forEach(item => item(event))
}
}
// 将来使用的时候
var o = new Observer()
// 订阅事件
o.on('click', handlerA)
o.on('click', handlerB)
o.emit('click', 'hello world', 100, true, { name: 'Jack' })
// 准备几个事件处理函数, 因为我老要用到, 先准备好
function handlerA(e) { console.log('我是事件处理函数 handlerA', e) }
function handlerB(e) { console.log('我是事件处理函数 handlerB', e) }
function handlerC(e) { console.log('我是事件处理函数 handlerC', e) }