js设计模式分享

js设计模式:

了解设计模式:

1、什么设计模式:针对特定的问题,给出简洁而优化的处理方案

2、市场上常用的设计模式:单例模式、 组合模式、 观察者模式、 适配器模式、 代理模式、 工厂模式、 构建模式

3、今天主要分享单例模式、组合模式和观察者模式

单例模式:让一个构造函数一辈子只有一个实例对象

单例模式的简单应用: 弹出层 alert() 比较丑, 用户体验极度不好, 好多网站会使用一个自己写的 div 盒子, 当作弹出层,再自己写的过程中, 一个网站不可能只弹出一次,不能每次弹出就创建一个 div,每次弹出的都是之前创造好的那个 div, 只是文字改变了,如果不用单例模式, 每次 new 就是创造一个 div,如果用了单例模式, 每次 new 都是用的第一次的 div, 只是改变文字内容

单例模式代码:

var Person = (function () {
// 真实的构造函数体
function Abc() {
this.name = 'Jack'
}
Abc.prototype.sayHi = function () {}
var instance = null
return function () {
return !instance ? (instance = new Abc()) : instance
}
})()
var p1 = new Person()
var p2 = new Person()
console.log(p1) // 是 Person 的一个实例, 是个对象
console.log(p2) // 是 Person 的一个实例, 是个对象
console.log(p1 === p2) // true

组合模式:把若干种启动方式一样的构造函数放在一起,准备一个总开关,总开关一启动,那么这些构造函数就都启动了

实现组合模式:需要一个承载所有构造函数实例的数组,需要一个方法,向数组里面添加内容,需要一个方法,能把数组里面的所有内容启动了

例子:米家:当你回家的时候,你一打开门,家里的所有东西就启动了,灯亮了,电视开了,空调开了窗帘拉开了...

// 一个构造函数的启动方式
class Light {
constructor() { }
// 这个构造函数的启动方法
init() {
console.log('灯亮了')
this.a()
this.b()
this.c()
}
a() { }

b() { }

c() { }
}
// 第二个构造函数
class Tv {
constructor() { }

init() {
console.log('电视开了')
}
}
class Air {
constructor() { }
init() {
console.log('空调开了')
}
}

// 组合模式的代码
class Compose {
constructor() {
// 用来承载每一个实例的数组
this.composeArr = []
}
// 向数组里面添加内容
add(instance) {
this.composeArr.push(instance)
}
// 把数组里面的每一个内容调用了
init() {
console.log('总开关启动了')
this.composeArr.forEach(item => item.init())
}
}
// c 就是一个总开关
var c = new Compose()
// 每一次执行 add 方法就是向总开关上添加内容
c.add(new Light())
c.add(new Tv())
c.add(new Air())
// 只要我的总开关一启动
// 里面的每一个构造函数就同时都启动了
c.init()
console.log(c)

观察者模式:又称发布/订阅模式

今天我从两个角度分析观察者模式

(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 ))
}
}
// 二、观察者
class Observer {
// constructor 就相当于 es5 的构造函数体 => 构造器
constructor (name) {
// 用它来标明一下我是班主任还是年级主任还是教务主任
this.name = name
}
// 方法, 就是这些老师能触发的技能
qingjiazhang (state) {
console.log(`我是 ${ this.name }, 因为你 ${ state } 了, 我要请你家长来!`)
}
}
var xiaoming = new Student() // 被观察者
var banzhuren = new Observer('班主任') // 观察者
var jiaowuzhuren = new Observer('教务主任') // 观察者
var nianjizhuren = new Observer('年级主任') // 观察者
// 让班主任看着小明
xiaoming.attach(banzhuren)
// 让教务主任看着小明
xiaoming.attach(jiaowuzhuren)
// 让年级主任看着小明
xiaoming.attach(nianjizhuren)
// 当小明状态改变的时候,就会触发 xiaoming.notify()
// 就会把 xiaoming.observers 这个数里里面的每一个对象的 请家长技能调用
xiaoming.setState('玩手机') // 对象调用方式, this -> 点前面是谁就是谁

(2)发布/订阅 角度

分成三个状态:订阅、取消订阅、发布

发布/订阅 需要的内容:准备一个消息盒子 => 订阅的方法(向消息盒子里添加内容)=>{

取消订阅的方法:把已经订阅的方法从消息盒子内部拿走

发布事件的方法:把消息盒子里面的对应的处理函数执行了

}

举例:假如我想买一本书

=> 我去到书店买, 如果书店没有

=> 我就和店员说一下, 等有了你给我打电话 -> 订阅 事件

=> 我就踏实的在家等着, 等电话

=> 一旦书店到了这本书, 就会给我打电话了 -> 由店员 发布 事件

=> 再中间时间的时候, 我的朋友送了我一本这个书

=> 我就告诉店员, 你来了这个书也不需要给我打电话了 -> 取消 订阅 事件

=> 我已经由了, 不需要你在告诉我了

代码:

// 准备几个事件处理函数, 因为我老要用到, 先准备好
function handlerA(e) { console.log('我是事件处理函数 handlerA', e) }
function handlerB(e) { console.log('我是事件处理函数 handlerB', e) }
function handlerC(e) { console.log('我是事件处理函数 handlerC', e) }
function handlerD(e) { console.log('我是事件处理函数 handlerD', e) }
function handlerE(e) { console.log('我是事件处理函数 handlerE', e) }
 
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
// a,b,c 后面的所有数据都是传递给事件处理函数里面使用的内容
// arg => arguments
// 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' })
关键字:设计模式,单例模式,组合模式,观察者模式

 

猜你喜欢

转载自www.cnblogs.com/dengdengya/p/12346574.html