前端_设计模式

文章介绍了前端开发中常见的几种设计模式,包括发布订阅模式用于事件传递,如Vue2的数据响应;观察者模式关注对象状态变化,类似Vue的数据劫持;单例模式确保全局唯一实例,如Vuex的全局状态管理;以及工厂模式简化对象创建,如根据用户角色动态生成页面。
摘要由CSDN通过智能技术生成

设计模式运用广泛,前端中也存在很多设计模式,将目前遇到过并且识别出的设计模型进行一下记录。

1.发布订阅模式

on:一般为订阅者命名,将异步函数加入数组,等待被执行;
emit:一般为发布者命名,从数组中取出异步函数,一次进行执行
发布订阅之间没有明显的关系,他们主要是靠中介(数组)。与下面的观察者模式有所区别。
【注】
目前了解的发布订阅模式的使用有:

  • vue2中的数据响应就是基于发布订阅模式实现的;
  • mqtt通信
  • websocket
class EventBus {
	constructor() {
		this.tasks = {};
	}
	// 1.订阅模式 - 根据type,进行存储数组
	on(type, cb) {
		if (!this.tasks[type]) {
			this.tasks[type] = [];
		}
		this.tasks[type].push(cb);
	}
	// 2.发布模式 - 根据type去除对应的数组,依次执行异步函数
	emit(type, ...args) {
		let arr = this.tasks[type];
		if (arr?.length) {
			arr.forEach((i) => i(args)); // 注意this指向);
		}
	}
	// 3.删除事件
	off(type, fn) {
		this.tasks[type] = this.tasks[type].filter((item) => item !== fn);
	}
	// 4.只执行一次
  once(type, fn) {
		let f = (...args) => {
			fn(...args);
			this.off(type, f);
		};
		this.on(type, f); // 将f函数加入,则emit多次的时候,该函数执行完后立即被删除,达到了只运行一次的目的
	}
}
let bus = new EventBus();
let fn1 = (...args) => {
	console.log("订阅了1", ...args);
};
let fn2 = (...args) => {
	console.log("订阅了2", ...args);
};
bus.on("change", fn1);
bus.once("change", fn2);
// bus.off("change", fn2); // 取消了fn2的订阅,则后续无法执行对应的异步函数
bus.emit("change", 1, 2, 3);
bus.emit("change", 1, 2, 3);
bus.emit("change", 1, 2, 3);

遗留问题:那先订阅后发布如何实现?
待看

2.观察者模式

是观察者和被观察者的关系,一旦被观察者的属性发生了变化,则会通知观察者,做出相应的动作。
【注】
类似于vue2中数据响应式更新的数据劫持,在get阶段收集依赖,然后在set阶段触发依赖,实现对应的依赖异步函数依次执行,实现数据变化触发视图更新。

// 被观察者
class Subject {
	constructor(name) {
		this.name = name;
		this.state = "非常开心";
		this.observers = [];
	}
	// 1.收集观察者(有没有觉得很像订阅)
	attach(o) {
		this.observers.push(o);
	}
	setState(state) {
		this.state = state;
		// 2.一更新状态,则会主动通知观察者
		this.observers.forEach((item) => {
			item.update(this);
		});
	}
}
// 观察者
class Observer {
	constructor(name) {
		this.name = name;
	}
	update(baby) {
		console.log(`当前:${this.name}被通知了,小宝宝状态变化:` + baby.state);
	}
}
// 简单的例子:观察者,需要观察小宝宝的心理变化
let baby = new Subject("baby");
let father = new Observer("father");
let mother = new Observer("mother");
baby.attach(father); //把观察者加入到被观察中
baby.attach(mother);
baby.setState("被欺负了");
// 当前:father,知道了小宝宝状态变化:被欺负了
// 当前:mother,知道了小宝宝状态变化:被欺负了

3.单例模式

单例模式两个条件
(1)确保只有一个实例
(2)可以全局访问
【注】 适用场景:“单例模式的特点,意图解决:维护一个全局实例对象。”

  • 引用第三方库(多次引用只会使用一个库引用,如 jQuery)
  • 弹窗(登录框,信息提示框)
  • 购物车 (一个用户只有一个购物车)
  • 全局态管理 store (Vuex )
class MyObject {
	constructor(name) {
		this.name = name;
		return this.name;
	}
	static getInstance(name) {
		if (!this.instance) {
			this.instance = new MyObject(name);
		}
		return this.instance;
	}
}
let obj = MyObject.getInstance("mm");
console.log(obj.__proto__ === MyObject.prototype);

4.工厂模式

  • 工厂模式是用来创建对象的一种最常用的设计模式。
  • 在实际的前端业务中,最常用的简单工厂模式。
  • 什么时候会用工厂模式?将new操作简单封装,遇到new的时候就应该考虑是否用工厂模式。
//1.简单工厂模式/静态工厂模式
// 前端应用:根据用户的权限来渲染不同的页面
class userFactory { 
  constructor(name,pages) {
    this.name = name;
    this.viewPages = pages
  }
 static getInstance(roleEn) { 
    switch (roleEn) {
      case "admin":
        return new userFactory('超级管理员',['主页','用户信息页'])
      case "normal":
        return new userFactory('超级管理员', ['用户信息页'])
      default: return null
     }
  }
}
let admin = userFactory.getInstance('admin')
let normal = userFactory.getInstance('normal')
//2.vue中的实现根据用户类型返回不同的路由权限
//2.1routerFactory.js
import SuperAdmin from '../components/SuperAdmin.vue'
import NormalAdmin from '../components/Admin.vue'
import User from '../components/User.vue'
import NotFound404 from '../components/404.vue'
let AllRoute = [
  //超级管理员页面
  {
    path: '/super-admin',
    name: 'SuperAdmin',
    component: SuperAdmin
  },
  //普通管理员页面
  {
    path: '/normal-admin',
    name: 'NormalAdmin',
    component: NormalAdmin
  },
  //普通用户页面
  {
    path: '/user',
    name: 'User',
    component: User
  },
  //404页面
  {
    path: '*',
    name: 'NotFound404',
    component: NotFound404
  }
]
let routerFactory = (role) => {
  switch (role) {
    case 'superAdmin':
      return {
        name: 'SuperAdmin',
        route: AllRoute
      };
    case 'normalAdmin':
      return {
        name: 'NormalAdmin',
        route: AllRoute.splice(1)
      }
    case 'user':
      return {
        name: 'User',
        route:  AllRoute.splice(2)
      }
    default: 
      throw new Error('参数错误! 可选参数: superAdmin, normalAdmin, user')
  }
}
export { routerFactory }
//2.2Login.vue
import {routerFactory} from '../router/routerFactory.js'
export default {
  //... 
  methods: {
    userLogin() {
      //请求登陆接口, 获取用户权限, 根据权限调用this.getRoute方法
    },
    getRoute(role) {
      //根据权限调用routerFactory方法
      let routerObj = routerFactory(role);
      //给vue-router添加该权限所拥有的路由页面
      this.$router.addRoutes(routerObj.route);
      //跳转到相应页面,注,因为使用this.$router.addRoutes方法添加的路由刷新后不能保存,所以会导致路由无法访问。
      //通常的做法是本地加密保存用户信息,在刷新后获取本地权限并解密,根据权限重新添加路由。
      this.$router.push({name: routerObj.name})
    }
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值