JS常见的设计模式
单例模式
点击查看代码
<script>
// 单例模式 => 自始至终都只能创建一个对象 让对象唯一存在
let Wife = (function(){
class Person{
constructor(name){
this.name = name
}
}
let instance = null
function getInstance(name){
// 获取实例的方法
if(!instance) instance = new Person(name)
return instance
}
// 返回创建实例函数
return getInstance
})()
// 单例模式
const w1 = Wife("冰冰")
const w2 = Wife("菲菲")
console.log(w1); //冰冰
console.log(w2); //冰冰
console.log(w1 === w2); //true
</script>
使用单例模式实现一个简易版的vuex3
<body>
<button onclick="fn1()">++</button>
<button onclick="fn2()">--</button>
<p></p>
<script>
// 使用单例模式实现一个简易版的vuex3
let Utils = (function(){
// 存储数据的
let state = {
count:1
}
// 操作数据
function mutation(payload){
// 如果payload => increment 我们就让state.count++
switch(payload){
case "increment":
state.count++
break
case "decrement":
state.count--
break
}
// 如果payload => decrement 我们就让state.count--
}
// 将数据返回到外部
function getState(){
return state //返回一个对象
}
return { //返回两个函数构成的对象
mutation,
getState
}
})()
console.log(Utils === Utils);
// 获取仓库里面的数据源
function fn(){
const p = document.querySelector("p")
// 获取数据源
p.innerHTML = Utils.getState().count
}
fn()
// 点击++ 让仓库里面的数据++
function fn1(){
// 让仓库里面的count++
Utils.mutation("increment")
// 渲染到页面
fn()
}
// 点击-- 让仓库里面的数据--
function fn2(){
// 让仓库里面的count--
Utils.mutation("decrement")
// 渲染到页面
fn()
}
</script>
</body>
作用:确保一个类只有一个实例对象,让对象唯一存在
应用场景:在需要共享资源或管理全局状态的情况下,如数据库连接池、线程池、全局配置等
组合模式
点击查看代码
<script>
// 组合模式 => 将拥有相同功能的实例对象存储到一个队列当中 一起执行
class haha{
// 如果我们没有写constructor的时候 那么在ES6的类当中 存储在一个默认的没有参数的constructor
today(){
console.log("开心,哈哈哈哈哈");
}
}
class heihei{
today(){
console.log("开心,嘿嘿嘿嘿嘿");
}
}
class xixi{
today(){
console.log("开心,嘻嘻嘻嘻嘻");
}
}
class Comb{
constructor(){
this._message = [] //存储多个拥有相同功能的实例对象
}
add(instance){
// 每执行一次add函数 那么就往message盒子里面放入一个实例对象
this._message.push(instance)
}
execute(){
this._message.forEach(item=>{
item.today()
})
}
}
const ha = new haha()
const hei = new heihei()
const xi = new xixi()
const comb = new Comb()
comb.add(ha)
comb.add(hei)
comb.add(xi)
// 批量执行
c.execute()
</script>
参考:详解组合模式
作用: 将拥有相同功能的实例对象存储到一个队列当中,一起执行
应用场景:客户端可以忽略组合对象与单个对象的差异;优化处理树形结构、文件目录、菜单、导航
策略模式
点击查看代码
<script>
// 将一组数据结构(算法)封装起来,对外暴露一个统计的结构(增删改查)
let Util = (function(){
//定义一组折扣方案
let calcType = {
"80%": price => price *= 0.8,
"70%": price => price *= 0.7
}
//实现折扣
function inner(type,price){
//如果没有这种折扣方案,那么报错
if(!calcType[type]) throw new Error("没有这种折扣方案!")
//如果有这种折扣方案
// calcType[type] => 就是一个函数 price => price *= 0.7
return calcType[type](price)
}
//显示所有的折扣方案
inner.show = () =>{
return calcType
}
//添加一种折扣方案
inner.add = (type,fn) =>{
calcType[type] = fn
}
//删除一种折扣方案
inner.remove = (type) =>{
if(!calcType[type]) throw new Error("没有这种折扣方案")
delete calcType[type]
}
return inner;
})()
//添加一种折扣方案
Util.add("-50",price => price -= 50)
//删除一种折扣方案
Util.remove("80%")
// 显示所有的折扣方案
console.log(Util.show());
// console.log(Util("-50",1000));
// console.log(Util("80%",1000));
</script>
作用:将一些相似的算法都封装成起来然后暴露给外部使用,使得这些算法可以独立于客户端变化
应用场景:在需要根据不同的策略来完成特定任务的情况下,如排序算法、支付方式选择等
观察者模式
点击查看代码
<script>
//定义观察者
class Observer{
constructor(){
//$message => 指的就是消息盒子
this.$message = {}
}
//订阅消息 => 往消息盒子里面添加自定义事件
$on(type,fn){
if(this.$message[type]){//第一次往消息盒子里面添加自定义事件
this.$message[type].push(fn)
}else{
this.$message[type] = [fn]
}
}
//取消订阅 => 将消息盒子里面对应的事件函数给删除掉
$off(type, fn) {
// 1. 先判断消息盒子里面是否存在事件类型
if (!this.$message[type]) throw new Error("请先订阅消息!")
// 2. 遍历消息盒子里面对应事件类型的函数
const arr = this.$message[type];
for (let i = 0; i < arr.length; i++) {
// 3. 如果事件函数中存在着传入进来的事件
// 那么就删除这个事件
if (arr[i] === fn) {
arr.splice(i, 1)
}
}
}
//清除订阅 => 将消息盒子里面的事件类型给删除
$clear(type){
//判断消息盒子里面是否存在事件类型
if(!this.$message[type]) throw new Error("请先订阅消息!")
//清除订阅
delete this.$message[type]
}
}
const o = new Observer()
function fn1(){
console.log("我是一个函数1");
}
function fn2(){
console.log("我是一个函数2");
}
//订阅消息
o.$on('shop',fn1)
o.$on('shop',fn2)
//取消订阅
o.$off("shop", fn1)
//清除订阅
o.$clear('shop')
console.log(o);
</script>
作用:定义对象间的一种一对多依赖关系,当一个对象的状态发生变化时,它的所有依赖对象都会收到通知并自动更新。
应用场景:在需要实时更新或同步信息的情况下,如用户界面中的事件处理、消息订阅等
工厂模式
作用:一种用来创建对象的设计模式
应用场景:需要批量生产同种类的对象的时候