这是我参与「第四届青训营 」笔记创作活动的的第3天 主要内容为设计模式
1.设计模式的定义
设计模式是软件设计中常见问题的解决方案模型
- 是历史经验的总结
- 与特定语言无关
2.设计模式分类
一共有23中设计模式
- 创建型-如何创建一个对象
- 结构型-如何灵活的将对象组装成较大的结构
- 行为型-负责对象间的高效通信和职责划分
3.浏览器中的设计模式
1.单例模式
- 定义:全局唯一访问对象
- 应用场景:应用于缓存,全局状态管理等。
用单例模式实现请求缓存
写法1
import {api} from './utils'
//1.传统的类的写法
export class Request{
static instance:Request;
private cache:Record<string,string>;
constructor()
{
this.cache={}
}
static getInstance()
{
if(this.instance)
{
return this.instance
}
this.instance=new Request();
return this.instance;
}
public async request(url:string)
{
if(this.cache[url])return this.cache[url];
const response=api(url);
this.cache[url]=response;
}
}
写法2
const cache:Record<string,string>={}
export const request=async(url:string)=>{
if(cache[url]){
return cache[url]
}
const response=await Api(url)
cache[url]=response;
return response;
}
写法2与写法1相比没有采用传统的类的方式来实现
2.发布订阅模式
- 定义:一种订阅机制,可在被订阅对象发生变化时同之订阅者。
- 应用场景:从系统架构之间解耦,到业务中一些实现模式,像邮件订阅,上线订阅等,应用广泛。
用发布订阅实现用户上线订阅
type Notify=(user:User)=>void;
export class User{
name:String;
status:"offline"|"online";
followers:{user:User;notify:Notify}[];
constructor(name:String)
{
this.name=name;
this.status="offline";
this.followers=[]
}
subscribe(user:User,notify:Notify)
{
this.followers.push({user,notify})
}
online()
{
this.status='online';
this.followers.forEach(item=>item.notify(item.user));
}
}
4.js中的设计模式
1.原型模式
- 定义:复制已有对象来创建新的对象
- 应用场景:js中对象创建的基本模式
用原型模式创建上线订阅中的用户
type Notify=(user:User)=>void;
export class User{
name:String;
status:"offline"|"online";
followers:{user:User;notify:Notify}[];
constructor(name:String)
{
this.name=name;
this.status="offline";
this.followers=[]
}
subscribe(user:User,notify:Notify)
{
this.followers.push({user,notify})
}
online()
{
this.status='online';
this.followers.forEach(item=>item.notify(item.user));
}
}
const baseUser:User={
name:"",
status:'offline',
followers:[],
subscribe(user,notify)
{
this.followers.push({user,notify});
},
online()
{
this.status='online';
this.followers.forEach(item=>{
item.notify(this)
})
}
}
export const createUser=(name:string)=>{
const User:User=Object.create(baseUser)
User.name=name;
User.followers=[];
return User;
}
2.代理模式
- 定义:可自定义控制对原型对象的访问方式,并且允许在更新前后做一些额外处理
- 应用场景:监控,代理工具,前端框架实现等。
使用代理模式实现用户的发布订阅
//实现基本的user类
type Notify=(user:User)=>void;
class User{
name:string;
status:"offline"|"online";
followers:{user:User,notify:Notify}[];
constructor(name:string)
{
this.name=name;
this.status='offline';
this.followers=[];
}
subscribe(user:User,notify:Notify)
{
this.followers.push({user,notify});
}
online()
{
this.status="online"
}
}
export const createProxyUser=(name:string)=>{
const user=new User(name)
const proxyUser=new Proxy(user,{
set:(target,prop:keyof User,value)=>{
target[prop]=value;
if(prop==='status')
{
notifyStatusHandlers(target,value);
}
return true
}
})
const notifyStatusHandlers=(user:User,status:"online"|"offline")=>{
if(status==='online')
{
user.followers.forEach((item)=>{
item.notify(user)
})
}
}
return proxyUser
}
让online方法只更改state,后续其他的操作交给notifyStatusHandlers来处理,使用createProxyUser来创建user
3.迭代器模式
- 定义:在不暴露数据类型的情况下访问集合中的数据
- 应用场景:用来遍历数据结构入列表,树等。
用for of迭代自己创建的类树组件
class MyDomElement{
tag:string;
children:MyDomElement[];
constructor(tag:string)
{
this.tag=tag;
this.children=[];
}
addChildren(child:MyDomElement)
{
this.children.push(child)
}
[Symbol.iterator](){
const list=[...this.children]
let node;
return {
next:()=>{
while((node=list.shift())){
node.children.length>0&&list.push(...node.children);
return {value:node,done:false};
}
return {value:null,done:true};
}
}
}
}
5.前端框架中的设计模式
1.代理模式
用Vue实现计数器
传统的方法中 我们是监听click事件,在click事件中手动的通过innerHTML的方法将变化后的count值来更新视图。 而依靠代理模式 Vue将我们更改DOM属性的操作更新到了虚拟DOM上,然后通过diff算法来更新视图。并不是直接更新视图,而是代理到了虚拟DOM上。
2.组合模式
- 可以多个对象组合使用,也可以单个对象独立使用
- 应用场景:DOM,前端组件,文件目录,部门
总结
- 总结出抽象的模式相对比较简单,但是想要将抽象的模式套用到场景中却非常困难
- 现代编程语言的多编程范式带来更多的可能性
- 真正优秀的开源项目学习设计模式并不断实践