这是我参与「第四届青训营 」笔记创作活动的第3天
前端设计模式及应用
设计模式
- 设计模式就是软件设计中常见问题的方案模型,其具有两个特点:
- 从历史经验总结而来
- 与特定语言无关
设计模式的历史
-
最早有关设计模式的书籍:《模式语言:城镇、建筑、建造》1977
-
计算机中的设计模式:《设计模式:可复用面向对象软件的基础》1994
- 直到现在这本书中讲述的23种设计模式仍然是提到设计模式时不可避免谈论的内容
-
在中国,从2014年开始国内互联网大厂异军突起,迅猛发展,设计模式的搜索量激增数倍,后来直至今日设计模式仍然属于比较热门的计算机搜索词汇。
浏览器中的设计模式
单例模式
- 定义:单例模式表示全局唯一访问对象,也就是说在应用的各个位置均可以访问到的一个对象,并且访问的对象都是同一个实例。
- 应用场景:缓存,全局状态管理。例如浏览器中window对象就是单例
举个例子
-
使用单例模式实现请求缓存
-
在JavaScript中,使用static关键字定义getInstance函数用于创建对象,如果调用时没有实例就创建一个,有就直接返回,这样保证每次调用返回的都是同一个实例一次性来实现单例模式。
-
将缓存定义在其中,每次请求时先查看缓存中是否有已经请求过的响应,有就直接返回不发送请求,没有再发送真实请求并且将响应结果存进缓存。
发布订阅模式
- 定义:一种订阅的机制,可以在订阅对象发生变化时,通知订阅者。
- 应用场景:邮件订阅,好友上限订阅等等。
用户上线订阅举例
-
如图一,Notify类型为一个函数,传入一个user表示上线的用户,该函数通知要被通知的用户
-
User类存储用户名,用户状态(在线、离线),以及订阅该用户的用户列表,该列表存储订阅该用户的用户对象和通知函数
-
当user1希望订阅user2,则调用user1.subscribe(user2, callUser1);
此函数会在user2的followers中添加user2和通知函数。
-
当user2上线时,首先会将user2的状态设置为在线,同时遍历user2的follower,调用通知函数,此时由user2调用callUser1函数通知user1:user2上线了
JavaScript中的设计模式
- 三种:原型模式、代理模式、迭代器模式
原型模式
- 通过复制已存在的对象来创建新的对象
-
和上一个版本不同,这次版本创建了一个原型用户baseUser用于创建其他用户,通过Object.creat(baseUser)将baseUser复制一份再通过一些操作创建一个新的对象,这就是原型模式
代理模式
-
一般而言,在程序设计开发过程当中,希望做到在一个函数中仅实现一个功能,而在实际开发中很难做到,例如需要监控所有的http请求,在很多位置添加日志,导致很多时候不得不修改业务代码加入这些附属功能。因此出现了代理模式,通过代理的方式添加日志,监控请求,处理副作用。
-
用代理模式将用户上线订阅重写:
-
在online函数中去除了分发订阅消息的语句,onlion函数仅实现更改用户在线状态,新增了一个创建代理用户的方法在代理中进行消息分发。
-
在createProxyUser函数中利用JavaScript的Proxy对user对象进行代理,劫持对status的更改,当status被改为online时,调用notifyStatusHandlers函数将user上线的消息分发出去。
前端框架中的设计模式
- 代理模式、组合模式
代理模式
- 此处的代理模式与上述JavaScript中的代理模式有所不同
- 在Vue框架中,利用了代理模式进行对DOM树的动态渲染
举个例子
-
在Vue中实现简单的计数器
在点击button的过程中,显示的值会随着点击次数增加而增加,如果打开开发者选项看,可以发现每次点击时仅有最少的元素发生了变化,如何实现的?
如果直接使用innerText或者innerHTML进行修改,则渲染流程是修改DOM属性=>视图更新
而Vue框架中,将整个DOM树代理了,在Vue中修改某个属性是在代理的DOM树上进行修改,而Vue对修改的内容进行检查,将发生变化的部分单独渲染到真正的DOM树上,这是Vue框架中的代理模式。
组合模式
- 可以多个组件组合使用,也可以单个组件独立使用
- 主要体现在React框架中的组合
举个例子
-
定义一个按钮组件:
在组合中进行使用
将Count组件与Header组件、Footer组件组合使用,建立一个基本的网页,同时如果其他地方有用到Count组件也可以直接进行组合,这就是React中的组合模式。
总结
- 设计模式不是银弹
- 设计模式并不能解决所有的问题,从业务中抽象出设计模型相对简单,但是想要将设计模型套用在实际的场景中却可能十分困难。
- 现代语言的多编程范式为设计模式提供了无限可能。
- 向优秀的开源项目学习模式设计并不断实践。