设计模式的根本:找到代码当中的变与不变,把它分离开来,使得变的部分更加的灵活,不变的部分更加稳定。
单例模式
说明:定义一个类,生成一个实例,而且整个项目仅此一个实例;
// 实践案例说明 axios的使用 axios就属于一种单例模式
// 比如封装axios做我们的请求
utils/request.ts
// 定义一个类
class HttpRequest {
instance:AxiosInstance;
constructor(options:CreateAxiosOptions){
this.instance = axios.create(options)
}
setHeader(){...}
get(){...}
post(){...}
put(){...}
delete(){...}
}
// 生成一个实例
const request = new HttpRequest({});
// 全局仅用这么一个请求实例
export default request;
// 使用当前的请求实例
import request '@/utils/request';
const fetchData = (url)=>{
return request.get(url)
}
简单 工厂模式
目的是:更方便去创建实例,而且每个实例都是独立并全新的;
// 实践案例 axios.create() 目的:每次使用这个方法的时候都是返回一个全新的实例;
// 原理部分
class Axios {};
class A {
create(){
return new Axios();
}
}
const axios = new A();
export default axios; // 导出// 如何使用
import axios from 'axios';
// 创建很多实例,他们都是各自独立的
const httpRequest1 = axios.create();
const httpRequest2 = axios.create();
const httpRequest3 = axios.create();
策略模式
说明:依据不同的策略去做不同的事情;比如存在很多if else这种代码的情况;
// 比如需要依据不同的年龄端去做不同的处理
// 以下的坏处:可读性很差、可维护性差、可拓展性差;
const doSomething = (age:number) =>[
if (age === 20){
// doSomething
}else if (age === 30){
// doSomething
}else if (age ===40) {
// doSomething
}else{
// doSomething
}
]
// 通过map存储,好拓展
const doMap : Record<number,Function> = {
20:()=>{},
30:()=>{},
40:()=>{},
50:()=>{},
}
const doSomething = (age:numbner)=>[
doMap[age]?.()
]
适配器模式
说明:数据需要做格式转化、格式统一的时候;
// 比如一一个场景,后端返回了三种数据格式,前端需要把这三种格式转换界面所需要的格式;
const data1 = [{age1:10,name1:'汪子'}];
const data2 = [{age2:20,name2:'jessica'}];
const data3 = [{age3:40,name3:'小明'}];// 依据三种不同的格式,写出3个类去进行适配,所谓的适配类
class Adapter1 {
data: { age1: number ,name:string}
constructor(data){
this.data = data
}
transform(){
return this.data.map(
({age1,name1})=>({
age:age1,
name:name1
})
)
}
}
class Adapter2 {...} // 同上
class Adapter2 {...} // 同上// 当需要转换数据的时候,调用这些类就好了
const adapter1 = new Adaper1(传入data);
const newData = adapter1.transform();
装饰器模式
说明:定义一个类,在不改变这个类的前提下,去拓展这个类的功能;其实相当于创建新的类;
这里需要仔细与“继承”做好区分,研究的时候也困惑过,建议自行了解清楚
// 比如以下实践
// 我先定义一个不同的类别 人类
class Person {
say(){
alert('我是一个人类')
}
}// 我需要在这个普通人类拓展一个身份,老师
class Teacher{
person:Person
consturctor(person){
this.person = person
}
say(){
this.person.say();
alert('我也是一个老师')
}
}const p1 = new Person(); p1.say() ; // 我是一个人类
const t1 = new Teacher(p1) ; t1.say() // 我是一个人类 我也是一个老师
代理模式
说明:为我们的对象提供一个代理,以便控制对这个对象的访问,不能直接访问目标对象;
// 最好的实践案例就是ES6里面的Proxy,它就是最好的代理模式案例
const handler = {
get:function(obj,prop){
return prop in obj ? obj[prop] :7;
} x
}
const p = new Proxy({},handler);
p.a = 1;
p.b = undefined;
console.log(p.a,p.b) // 1 undefined
console.log('c' in p,p.c) // false 7
观察者模式
说明:(相互依赖)定义对象之间的一对多的依赖关系,当一个对象状态发生改变时,依赖它的其他对象都会得到通知;
观察者模式的发布和订阅时相互依赖的;
// 定义被观察者
class Dep {
status : string
observers: any[]
constructor(observer){
this.status = '不开心';
this.observers = [];
}
// 获得subject的状态
get(){ }
// 重新设置subject的状态
set(status){
this.status = status;
this.notify();
}
// subject状态更新,需要通知到所有观察者并调用其更新方法
notify(){
this.observer.forEach(item=>{item.update(this)})
}
push(observer){
this.observers.push(observer);
}
}// 定义观察者
class Observer {
name:string
constructor(name,subject){
this.name = name;
this.subject.push(this);
}
update(subject){
console.log(`${subject.status}发生变化了,${this.name}观察了`)
}
}const dep = new Dep();
const observer1 = new Observer('观察者1',dep);
const observer2 = new Observer('观察者2',dep);// 如何进行
subject.set('开心')
发布订阅模式
说明:发布订阅模式时不相互依赖的,因为有一个统一调度中心;
// Vue 的EventBus就是发布订阅模式
class EventBus {
callbackId
callbackList
constructor(){
this.callbackId = 0;
this.callbackList = {};
}
// 订阅 并返回删除的事件
on(name,fn){
if(!this.callbackList[name]){ this.callbackList[name] = [];}
if(this.callbackList[name]){ this.callbackId++;}
this.callbackList[name][this.callbackId] = fn
const off = ()=>{
delete this.callbackList[name][this.callbackId];
if(Object.keys(this.callbackList[name].lenght) == 0){ delete this.callbackList[name]}
}
return {off}
}
// 发布
emit(name,arg){
if(this.callbackList[name]){
for(let id in this.callbackList[name]){
this.callbackList[name][id](arg)
}
}else{
console.log(this.callbackList[name] + 'not found')
}
}
// 仅仅订阅一次就不再接受信息
once(name,fn){
const onceFn = (arg)=>{
if(fn){ fn(arg); }
fn = null
}
this.on(name,onceFn);
}
}const event = new EventBus();
event.on('hyy',(arg)=>{
console.log('hyy订阅了' + arg)});
event.emit('hyy','哈哈')event.once('oncetime',(arg)=>{
console.log('一次订阅了' + arg)});
event.emit('oncetime','哈哈')
event.emit('oncetime','呜呜')