一、认识单利模式(设计模式)
- 设计模式:为了 实现某一类功能的一个简洁优化的写法
(一)单利模式
- 一个构造函数(类), 一生只能有一个实例化对象
(二)案例需求
- 一个构造函数, 在实例化对象时, 判断是否为第一次实例化
- 是第一次创建一个实例化对象, 然后返回
- 不是第一次想办法拿到第一次的实例化对象, 然后返回
(三)解决方法
- 拿一个变量, 初始值给一个null
- 在实例化对象时, 第一次实例化, 直接将实例化赋值给变量, 然后将变量返回
- 后续再实例化的时候, 直接返回刚才的变量
(四)核心代码
class Dialog {
constructor(title) {
console.log('创建一个弹出框插入到页面中, 类型为: ')
this.title = title
}
}
let instance = null
function newDialog(type) {
if (instance === null) {
instance = new Dialog(type)
}
return instance
}
const n1 = newDialog('警告')
console.log(n1)
const n2 = newDialog('文本')
console.log(n2)
二、单例模式变形
1、代码的问题
1. 全局多了一个变量instance
2. 传递多个参数 ,无法生效
3. 构造函数的类, 和实际使用创建的函数, 不是一个名字
2、通过闭包, 解决问题1
class Dialog {
constructor(title) {
console.log('创建一个弹出框插入到页面中, 类型为: ')
this.title = title
}
}
function fn(type) {
let instance = null
return function newDialog() {
if (instance === null) {
instance = new Dialog(type)
}
return instance
}
}
const n1 = fn('警告')
const res = n1()
console.log(res)
class Dialog {
constructor(title) {
console.log('创建一个弹出框插入到页面中, 类型为: ')
this.title = title
}
}
// 利用自执行函数 进一步优化
const newDialog = (function fn() {
let instance = null
return function inner(type) {
if (instance === null) {
instance = new Dialog(type)
}
return instance
}
})()
const n1 = newDialog('警告')
console.log(n1)
const n2 = newDialog('文本')
console.log(n2)
3、解决问题2:传递多个参数 ,无法生效
class Dialog {
constructor() {
console.log('创建一个弹出框插入到页面中, 类型为: ')
this.title = ''
}
// 每次需要给title赋值, 直接调用这个方法即可
init(title) {
this.title = title
console.log('当前title的值为: ', title)
}
}
const newDialog = (function fn() {
let instance = null
return function inner(type) {
if (instance === null) {
instance = new Dialog()
}
instance.init(type)
return instance
}
})()
const n1 = newDialog('警告')
console.log(n1)
const n2 = newDialog('文本')
console.log(n2)
4、解决 问题3:构造函数的类, 和实际使用创建的函数, 不是一个 名字
const Dialog = (function fn() {
let instance = null
class Dialog {
constructor() {
console.log('创建一个弹出框插入到页面中, 类型为: ')
this.title = ''
}
// 每次需要给title赋值, 直接调用这个方法即可
init(title) {
this.title = title
console.log('当前title的值为: ', title)
}
}
return function inner(type) {
// 1. 自动帮我们创建一个对象, 自动帮我们把函数内部的this指向这个新建对象
// 2. 手动往对象上添加属性
// 3. 自动返回一个对象
// 4. 构造函数内部不要写return, 返回一个基本数据类型, 写了和没写一样,
// 如果返回一个引用数据类型, 写了构造函数就没用了
if (instance === null) {
instance = new Dialog()
}
instance.init(type)
return instance
}
})()
// // 单例模式, 一般不建议写 new
const n1 = Dialog('警告')
const n2 = Dialog('文本')
const n3 = Dialog('红色警告')
console.log(n1)
console.log(n2)
console.log(n3)
console.log(n1 === n2)
console.log(n2 === n3)
console.log(n1 === n3)
三、策略模式
- 核心: 减少过多的 if...else...
- 需求: 去购物, 购物总价1987 折扣: 8折 7折 300-30 500-50
- 策略模式处理: 有一个数据结构,内部存储着各种折扣对应的计算总价方式
// 70% '300-30' '500-50' 60% 75%
let type = '80%';
let total = 1987;
if (type === '80%') {
} else if (type === '70%') {
} else if (type === '300-30') {
} else if (type === '500-50') {
} else if (type === '60%') {
} else if (type === '75%') {
}
(一)基础版
const price = (function(){
let PriceList = {
// '80%': (total) =>{}
'80%': total =>total * 0.8,
'70%': total =>total * 0.7,
}
return function inner(type, total){
// console.log('inner函数开始执行,计算商品总价');
// console.log(type);
// console.log(PriceList[type]);
// console.log(PriceList[type](total));
return PriceList[type](total)
}
})()
let newPrice1 = price('80%', 1000);
let newPrice2 = price('70%', 1000);
console.log(newPrice1);
console.log(newPrice2);
(二)进阶版
const price = (function(){
let PriceList = {
// '80%': (total) =>{}
'80%': total =>total * 0.8,
'70%': total =>total * 0.7,
}
return function inner(type, total){
// 新增其他折扣时
inner.add = (key, value) =>{
PriceList[key] = value;
}
// 只传递一个参数时
inner.sub = (key) =>{
PriceList[key] = null
}
// 打印PriceList列表时
inner.GetList = () =>{
return PriceList
}
return PriceList[type](total)
}
})()
let newPrice1 = price('80%', 1000);
let newPrice2 = price('70%', 1000);
price.add('60%', total =>total * 0.6);
let list = price.GetList();
console.log(newPrice1);
console.log(newPrice2);
console.dir(price);
四、发布订阅模式
- 这个模式适用于大型项目的封装
- 自行搜索: Vue2 响应式原理
- 除了 发布订阅模式, 还有一种叫观察者模式,这两个开发模式, 特别相似
class observer {
constructor(name) {
// 模拟一个店员(不重要)
this.name = name
// 店员的记录手册
this.message = {}
}
// 原型
add(type, fn) {
if (this.message[type] === undefined) {
this.message[type] = []
}
this.message[type].push(fn)
}
tri(type) {
// 调用这个方法, 通知对应的 人员 来购买
// console.log(type)
// console.log(this.message[type])
this.message[type].forEach(item => {
// console.log(item)
item()
})
}
remove(type, fn) {
// console.log(type, fn)
// console.log(this.message[type], fn)
this.message[type] = this.message[type].filter(item => item !== fn)
}
}
const res = new observer('小方')
console.log('初始数据: ', res)
const fnA = () => {
console.log('我是张三, 我想购买这本书')
}
const fnB = () => {
console.log('我是李四, 我想购买这本书')
}
const fnC = () => {
console.log('我是王五, 我想购买这本书')
}
// 新增(留下联系方式)
res.add('JS从入门到入土', fnA)
res.add('JS从入门到入土', fnB)
res.add('颈椎病的预防', fnC)
// 书本到了, 通知对应的预约者, 前来购买
res.tri('颈椎病的预防')
// 某人, 取消预约一本书
res.remove('JS从入门到入土', fnA)
console.log(res)