大家好,欢迎来到IT知识分享网。
●为了解决一类问题给出的 简洁而优化 的解决方案
●设计模式不是规则,是程序员开发过程中的经验总结
单例模式
●一个构造函数一生只有一个 实例对象
<script> function Person(name) { this.name = name } // 核心代码 let instance = null function singleton() { if (!instance) instance = new Person('Jack') return instance } // 实现单例模式创建实例对象 // 第一次调用 singleton() 函数, 此时 instance 就是 null // if 条件为 true, 给 instance 赋值 // 赋值为一个 Person 的实例 // return instance, 把 instance 保存的值赋值给了 p1 // p1 拿到的是 Person 的实例 const p1 = singleton() // 第二次调用 singleton() 函数, 此时 instance 是Perosn 的实例 // if 条件为 false, 后面的代码不执行 // 直接执行 return instance // 又一次把 Person 的实例返回了 // 赋值给了 p2 变量 // p2 拿到的还是 Person 之前的哪一个实例 const p2 = singleton() console.log(p1, p2) console.log(p1 === p2) </script>
单例模式变形
●利用闭包和自执行函数结合的方式实现
function Person(name) { this.name = name } let instance = null function singleton() { if (!instance) instance = new Person('Jack') return instance } // 我们要以闭包的形式得到singleton 不让都暴露在全局 // 这里我们要使用的就是自执行函数 const singleton = (function outer() { function Person(name) { this.name = name } let instance = null return function inner() { if (!instance) instance = new Person('Jack') return instance } })() // const p1 = singleton() // const p2 = singleton() // console.log(p1, p2); // console.log(p1 === p2); // 到了这里我们该放进去的都放进去了接下来我们继续变形 /* Person这个变量名现在只在函数里面有作用 如果我现在把singleton变成Person 和里面的Person有没有影响? 是没有影响的 我们先不改变 为了好说 现在要弄明白一个问题 就是外面的singleton()调用的是那个函数 */ const singleton = (function outer() { function Person(name) { this.name = name } // 在Person的原型对象上定义一个方法 用来修改Person构造函数里面的name的值 Person.prototype.setName = function (val) { this.name = val } // 单例的核心代码 let instance = null return function inner(name) { if (!instance) instance = new Person() // 这里调用setName函数 instance.setName(name) // 这个位置的instance就是person的实例 return instance } })() // const p1 = singleton('Rose') console.log(p1); // const p2 = singleton('Jack') console.log(p2); console.log(p1 === p2); // 再次修改变量 const Person = (function outer() { function Person(name) { this.name = name } // 在Person的原型对象上定义一个方法 用来修改Person构造函数里面的name的值 Person.prototype.setName = function (val) { this.name = val } // 单例的核心代码 let instance = null return function inner(name) { if (!instance) instance = new Person() // 这里调用setName函数 instance.setName(name) // 这个位置的instance就是person的实例 return instance } })() // 所以这个时候我们写new也没有关系 // 因为return的是一个复杂数据类型 自动创建的能力没有了 const p1 = new Person('Rose') console.log(p1); const p2 = new Person('Jack') console.log(p2); console.log(p1 === p2);
<!-- 整个弹出层 --> <div class="dialog"> <!-- 顶部内容 --> <div class="top"> <p>提示</p> <span>X</span> </div> <!-- 中间内容区域 --> <div class="content"> 真实内容 </div> <!-- 底部区域 --> <div class="bottom"> <button>确定</button> </div> </div>
样式
.dialog { width: 600px; height: 360px; border-top: 1px solid #ccc; border-left: 1px solid #ccc; box-shadow: 1px 2px 2px 0px #ccc; background-color: #fff; position: fixed; top: 0; left: 0; right: 0; bottom: 0; margin: auto; display: flex; flex-direction: column; border-radius: 15px; } .dialog > .top { height: 45px; background-color: skyblue; display: flex; box-sizing: border-box; justify-content: space-between; padding: 0 20px; align-items: center; border-bottom: 1px solid #ccc; border-radius: 15px 15px 0 0; } .dialog > .top > p { font-size: 22px; font-weight: 700; color: #fff; } .dialog > .top > span { cursor: pointer; } .dialog > .bottom { height: 45px; display: flex; align-items: center; justify-content: center; border-top: 1px solid #ccc; } .dialog > .bottom > button { font-size: 20px; padding: 0 10px; cursor: pointer; } .dialog > .content { flex: 1; display: flex; justify-content: center; align-items: center; font-size: 20px; }
交互
// 书写单例模式代码 const Dialog = (function () { // 构造函数体 class Dialog { constructor () { this.dialog = document.createElement('div') // 顶部面板 this.top = null // 面板内的文本 this.desc = null // 中间的内容区域 this.content = null // 底部 this.bottom = null // 面本内的文本 this.descText = '提示' // 提示文本内容 this.title = '你好 世界' // 颜色和文本你对照表 this.list = [ { name: 'success', descText: '成功', bgColor: 'green' }, { name: 'danger', descText: '危险', bgColor: 'red' }, { name: 'warning', descText: '警告', bgColor: 'orange' }, { name: 'default', descText: '提示', bgColor: '#fff' }, { name: 'info', descText: '信息', bgColor: 'skyblue' } ] this.single() } // 只执行一次 single () { this.creHTML() this.setCss() this.bindEvent() } // 创建整体结构 creHTML () { // 创建 top 结构 this.top = document.createElement('div') this.desc = document.createElement('p') this.desc.innerText = this.descText this.span = document.createElement('span') this.span.innerText = 'X' // 把 p 和 span 插入到 top 内 this.top.appendChild(this.desc) this.top.appendChild(this.span) // 创建内容结构 this.content = document.createElement('div') this.content.innerText = this.title // 创建底部结构 this.bottom = document.createElement('div') this.btn = document.createElement('button') this.btn.innerText = '确定' this.bottom.appendChild(this.btn) // 把创建好的结构插入到 dialog 内 this.dialog.appendChild(this.top) this.dialog.appendChild(this.content) this.dialog.appendChild(this.bottom) // 把创建好的 dialog 结构插入到 页面内 document.body.appendChild(this.dialog) } // 设置 css 样式 setCss () { // 给 dialog 设置样式 setStyles(this.dialog, { width: '600px', height: '360px', 'border-top': '1px solid #ccc', 'border-left': '1px solid #ccc', 'box-shadow': '1px 2px 2px 0px #ccc', 'background-color': '#fff', position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, margin: 'auto', display: 'flex', 'flex-direction': 'column', 'border-radius': '15px', }) // 给 top 设置样式 setStyles(this.top, { height: '45px', 'background-color': 'skyblue', display: 'flex', 'box-sizing': 'border-box', 'justify-content': 'space-between', padding: '0 20px', 'align-items': 'center', 'border-bottom': '1px solid #ccc', 'border-radius': '15px 15px 0 0' }) // 给 content 设置样式 setStyles(this.content, { flex: 1, display: 'flex', 'justify-content': 'center', 'align-items': 'center', 'font-size': '20px' }) // 给 bottom 设置样式 setStyles(this.bottom, { height: '45px', display: 'flex', 'align-items': 'center', 'justify-content': 'center', 'border-top': '1px solid #ccc' }) // 给 面板提示 设置样式 setStyles(this.desc, { 'font-size': '22px', 'font-weight': 700 }) // 给 面板的 关闭按钮 setStyles(this.span, { cursor: 'pointer' }) // 底部按钮 setStyles(this.btn, { 'font-size': '20px', padding: '0 10px', cursor: 'pointer' }) } // 事件绑定 bindEvent () { this.btn.addEventListener('click', () => { this.dialog.style.display = 'none' }) this.span.addEventListener('click', () => { this.dialog.style.display = 'none' }) } // 每次都要执行 init (title = '', type = 'default') { // 根据你的 文本 和 关键字 设置内容 // 1. 根据类型获取到对照表内的对应信息 const info = this.list.find(item => item.name === type) || { name: 'default', descText: '提示', bgColor: '#fff' } // 2. 根据 info 的内容开始设置 this.top.style.backgroundColor = info.bgColor this.desc.innerText = info.descText this.descText = info.descText this.content.innerText = title this.title = title // 让 dialog 显示出来 this.dialog.style.display = 'flex' } } // 功能函数 function setStyles(ele, styles) { for (let k in styles) { ele.style[k] = styles[k] } } // 单例模式核心代码 let instance = null return function (...arg) { if (!instance) instance = new Dialog() instance.init(...arg) return instance } })()
发布订阅模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
/*
发布订阅模式
例子: 去书店买书
没有设计模式 就是面向过程
=> 去到书店 , 问有没有书 , 没有就回去了,
=> 过一会儿 , 在去书店问问有没有书 , 没有就回去
=> 过一会儿 , 在去书店问问有没有书 , 没有就回去
=> 过一会儿 , 在去书店问问有没有书 , 没有就回去
=> 过一会儿 , 在去书店问问有没有书 , 没有就回去
=> 过一会儿 , 在去书店问问有没有书 , 没有就回去
=> 过一会儿 , 在去书店问问有没有书 , 没有就回去
=> .....
=> 过一会儿 , 去到书店问问有没有书 , 有了 , 买回去
发布订阅模式
=> 去到书店 , 问有没有书 , 没有的话留下一个电话号码 , 有了给我打电话
=> 回去等待电话
=> 接到电话了去到书店把书买回去
发布订阅: 把你想要做的事情都写好(也就是注册到on函数中) , 将来一触发(就是执行了trigger函数)就都做完了
*/
// 代码实现
class Observer{
constructor(status){
// 表示你的初始状态 , 将来一旦这个状态发生了改变我们要触发
// 也就是一旦有书了要通知人来买
this.status = status
// 定义个消息盒子 , 记录的都有谁和我定了书
// 定了几本书 , 都有那些书 , 是不是要记录上啊
this.message = {}
}
// 在原型上定义几个方法
// 这个表示注册一个事件
// 下面函数调用了传递了实参 , 我们这里要接受形参
on (type,fn) {
// type 事件类型
// fn 事件处理函数
// 接下来我们要绑定在message内部
// 我们要判断message内部有没有type这个类型
// 如果没有我们就让它称为一个数组
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) // 把不一样的重新赋值 , 那就把一样的筛出去了
}
// 触发事件
trigger (type) {
// 首先要判断有没有这个事件 , 如果没有就什么都不做了
if(!this.message[type]) return
// 代码能执行到这里说明有这个事件
// 那接下来就触发这个事件就好了
// 里面就是每一个函数 , 直接调用就可以了
this.message[type].forEach(item => item())
}
}
// 实例化个对象
// 这就是一个第三方 , 你可以把这个当做是书店的店员
const o = new Observer('没有')
// console.log(o);
// 准备几个函数
function handlerA() { console.log('handlerA');}
function handlerB() { console.log('handlerB');}
function handlerC() { console.log('handlerC');}
// 向o 上注册一个事件
// js这本书来了 , 执行handlerA这个函数
o.on('js',handlerA)
o.on('js',handlerB)
o.on('css',handlerA)
o.on('css',handlerC)
o.on('html',handlerB)
o.on('html',handlerC)
console.log(o);
// 向 o 取消一个事件注册
// 也就是我从别的地方买到这本书了 , 不要在给我打电话了
o.off('js',handlerA)
// 都注册好了以后由店员来触发这个事件
o.trigger('js') // 表示js这本书来了 , 这样就触发了这个函数
</script>
</body>
</html>
const type = '80%' // '70%' '300-20' '500-50' if (type === '80%') { } else if (type === '70%') { console.log('逻辑实现'); } else if (type === '300-20') { console.log('逻辑实现'); } else if (type === '500-50') { console.log('逻辑实现'); } else if (type === '300-30') { console.log('逻辑实现'); }
策略模式
// 我们利用的还是闭包 const discount = (function () { // 留存一份数据结构 const discountList = { // 这里的数据要如何设计 // 需要有折扣类型和折扣以后的价格 // 标识:能计算出最后的价格(这里的将来需要调用实现 , 也就是这里需要一个函数) '80%':function (total) { return (total * 0.8).toFixed(2) } } // 因为要使用闭包 , 我们需要返回一个函数 function inner(total,type) { // 这里我们出计算方式 // 这里需要根据传递进来的折扣查看discountList中有没有这个折扣就好了 // 需要把 type 当做键来访问 discountList // 如果有返回的是一个函数 , 如果没有返回的是一个undefined // console.log(discountList[type]); // 判断有没有这个折扣 , 没有这个折扣就返回总价 if (!discountList[type]) return total // 代码能执行到这里说明是有这个折扣的 return discountList[type](total) - 0 } // 这里把inner函数当做一个对象来看待 , 向里面插入一些方法 // 添加一个方法 , 专门用来向 discountList内添加折扣类型 inner.add = function (type,fn) { // type:表示添加的折扣 // fn: 是一个函数,用来计算出最后的价格 // console.log(type); // console.log(fn); // 添加到 discountList中 discountList[type] = fn } // 添加一个方法 , 用来删除一种折扣 inner.remove = function (type) { // 删除掉这个折扣 delete discountList[type] } // 我们含可以把这个折扣的列表返回出去查看 inner.getList = function () { return discountList } // 这里返回inner函数 return inner })() // 将来使用 // const res = discount('总价','折扣类型') const res = discount(1000,'80%') console.log(res); // 将来使用添加的折扣 discount.add('300-20', price => price - parseInt(price / 300) * 20) // 添加完毕以后需要在下面计算 const res1 = discount(1000,'300-20') console.log(res1); // 查看折扣列表 const list = discount.getList() console.log(list);
案例-收银台
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
padding-left: 200px;
}
input, button {
outline: none;
}
ul, li {
list-style: none;
}
.addSale, .calc {
width: 200px;
height: 33px;
background-color: skyblue;
color: #fff;
cursor: pointer;
border: none;
margin: 30px;
}
input {
width: 300px;
height: 30px;
padding-left: 20px;
font-size: 22px;
display: block;
margin: 20px;
}
ul {
display: flex;
margin: 20px;
}
ul > li {
width: 120px;
height: 120px;
background-color: orange;
margin: 10px;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
font-size: 30px;
cursor: pointer;
}
ul > li.active {
background-color: skyblue;
}
p {
font-size: 100px;
color: red;
margin: 20px;
}
</style>
</head>
<body>
<button class="addSale">添加折扣类型</button>
<!-- 总价格 -->
<input type="text">
<!-- 折扣类型 -->
<ul>
<li class="active">1111</li>
<li>1111</li>
<li>1111</li>
</ul>
<button class="calc">计算总价</button>
<!-- 最终价格 -->
<p>0.00</p>
折扣名称(显示在按钮上的文本): <input type="text" class="type">
计算方式(总价以 x 表示): <input type="text" class="method">
<script>
/*
收银台
*/
// 0. 获取元素
const ulBox = document.querySelector('ul')
const calcBtn = document.querySelector('.calc')
const totalInp = document.querySelector('input')
const pBox = document.querySelector('p')
const addBtn = document.querySelector('.addSale')
const nameInp = document.querySelector('.type')
const methodInp = document.querySelector('.method')
// 0. 以策略模式的形式准备一个 折扣记录
const calcPrice = (function () {
// 折扣列表
const calcList = {
'80%': function (total) { return (total * 0.8).toFixed(2) },
'70%': function (total) { return (total * 0.7).toFixed(2) }
}
function inner(total, type) {
if (!calcList[type]) return '0.00'
return calcList[type](total)
}
inner.add = function (type, fn) {
calcList[type] = fn
}
inner.remove = function (type) {
delete calcList[type]
}
inner.getList = function () {
return calcList
}
return inner
})()
// 0. 准备变量
let type = ''
// 1. 拿到当前所有的折扣渲染 li
// 将来一旦折扣添加了, 需要重新渲染 li
bindHtml()
function bindHtml() {
// 1-1. 拿到折扣类型列表
const list = calcPrice.getList()
// 1-2. 利用 list 渲染 li
let str = ''
for (let k in list) {
str += `
<li data-type="${ k }">${ k }</li>
`
}
ulBox.innerHTML = str
}
// 2. 折扣类型的选择(排他)
tab()
function tab() {
ulBox.addEventListener('click', e => {
if (e.target.nodeName !== 'LI') return
// 所有的没有类名
for (let i = 0; i < ulBox.children.length; i++) {
ulBox.children[i].classList.remove('active')
}
// 当前这个有类名
e.target.classList.add('active')
// 记录下当前的折扣类型
type = e.target.dataset.type
})
}
// 3. 结算按钮的事件
calcBtn.addEventListener('click', () => {
// 3-1. 拿到总价
const totalPrice = totalInp.value - 0
// 3-2. 计算最终价格
const resultPrice = calcPrice(totalPrice, type)
// 3-3. 把最终价渲染
pBox.innerText = resultPrice
})
// 4. 添加折扣
// 我们只能期望用户给我们两个内容
// 折扣名称
// 计算方式
addBtn.addEventListener('click', () => {
// 4-1. 拿到折扣名称
const name = nameInp.value
// 4-2. 拿到公式
// 开始组装
const r = '(parseInt(' + methodInp.value + ')).toFixed(2)'
// 语法: eval(字符串)
// 作用: 把该字符串当做js代码来执行
// const res = eval(r)
// 开始添加了
calcPrice.add(name, x => eval(r))
// 4-3. 从新渲染一遍 li
bindHtml()
// 4-4. 把两个文本框清空
nameInp.value = ''
methodInp.value = ''
})
</script>
</body>
</html>
模块模式
●要是设计模式中的一种
● 模块模式可以指定类想暴露的属性和方法,并且不会污染全局。采用闭包的形式
// 定义个自执行函数 var Person = (function() { // 定义一个变量 var name = 'rose' // 定义一个函数(方法) function sayName() { console.log('我的名字是:',name) } // 返回一个对象 // 因为是自执行函数 , Person得到的就是一个对象 // return { // name: name, // sayName: sayName // } return { name, sayName } })() // 使用 console.log(Person); Person.sayName()
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/124092.html