JS 中的设计模式
本文章通过介绍常见模式的简介,UML 类图展示,代码示例方式介绍几种常见的设计模式
设计模式简介相关请访问前端需要了解的设计模式(1)
工厂模式
- 将
new
操作单独封装 - 遇到
new
时,就要考虑是否使用工厂模式 - 这种设计模式可以大大降低程序模块之间的耦合度,便于更加灵活的扩展和维护
工厂模式是一种使用工厂方法创建对象的设计模式,而不是指定创建对象的确切的类或构造函数
示例:当你在购买汉堡时,直接点餐,取餐,不会自己亲手做。商店要”封装”做汉堡的工作,做好直接给买家
1 | /** |
如上述代码,函数Product
能接受一个参数 name。通过函数Creator
的create
方法可以创建一个Product
实例。可以无数次调用这个函数每次返回都会包含三个方法。
工厂模式是为了解决多个类似对象声明的问题,也是为了解决实例化对象产生重复的问题。
- 优点:能解决多个相似的问题
- 缺点:不能知道对象的识别问题(对象的类型不知道)
应用场景:jQuery 中的$、Vue.component 异步组件、React.createElement 等
单例模式
- 系统中被唯一使用
- 一个类只有一个实例
- 单例模式提供了一种将代码组织为一个逻辑单元的手段,这个逻辑单元中的代码可以通过单一变量进行访问
实现方法:使用一个变量来标志当前是否已经为某个类创建过对象,如果创建了,则在下一次获取该类的实例时,直接返回之前创建的对象,否则就创建一个对象。
示例:登录框、购物车
1 | class Singleton { |
要实现一个单例模式的话,我们无非就是使用一个变量来标识该类是否被实例化,如果未被实例化的话,那么我们可以实例化一次,否则的话,直接返回已经被实例化的对象。
单例模式的优点:
- 可以用来划分命名空间,减少全局变量的数量
- 使用单例模式可以使代码组织更为一致,使代码容易阅读和维护
- 可以被实例化,且只能实例化一次
应用场景:jQuery 中的$、Vuex 中的 Store、Redux 中的 Store 等
适配器模式
- 旧接口格式和使用者不兼容
- 中间加一个适配转化接口
- 用来解决两个接口不兼容问题,由一个对象来包装不兼容的对象,比如参数转换,允许直接访问
1 | Class Adoptee { |
应用场景:Vue 的 computed、旧的 JSON 格式转换成新的格式等
装饰器模式
- 为对象添加新功能
- 不改变其原有的结构和功能
- 可以动态的给某个对象添加额外的职责,而不会影响从这个类中派生的其他对象
比方说,汽车的成本取决于它的功能数量。 如果没有装饰者模式,我们必须为不同的功能组合创建不同的类,每个类都有一个成本方法来计算成本。
1 | class Circle { |
代理模式
- 使用者无权访问目标对象
- 中间加代理,通过代理做授权和控制
- 为其他对象提供一种代理,便以控制对这个对象的访问,不能直接访问目标对象
1 | class ReadImg { |
代码中ProxyImg
函数使用自己的特权方法display
使用了目标对象的方法。
代理模式的优点
- 代理对象可以代替本体被实例化,并使其可以被远程访问
- 它还可以把本体实例化推迟到真正需要的时候,对于实例化比较费时的本体对象,或者因为尺寸比较大以至于不用时不适于保存在内存中的本体,我们可以推迟实例化该对象。
使用代理模式实现预加载
1 | class MyImg { |
应用场景:网页事件代理、jQuery 的$.proxy、ES6 的 Proxy
代理模式 | 适配器模式 |
---|---|
提供一个一摸一样的接口 | 提供一个不同的接口 |
代理模式 | 装饰器模式 |
---|---|
显示原有功能但是经过限制或者阉割之后的 | 扩展功能,原有功能不变且可直接使用 |
外观模式
- 为了子系统中的一组接口提供了一个高层接口
- 使用者使用这个高层接口
- 为一组复杂的子系统接口提供一个更高级的统一接口,通过这个接口使得对子系统接口的访问更容易,不符合单一职责原则和开放封闭原则
1 | class A { |
应用场景:JS事件不同浏览器兼容处理,同一方法可以传入不同参数兼容处理
观察者模式
- 观察者也可称为发布&订阅模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主体对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。
- 观察者模式和发布&订阅者模式区别:本质上的区别是调度的地方不同
- 观察者模式:目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。具体观察者和具体目标继承各自的基类,然后具体观察自己注册到具体目标里。在具体目标发生变化的时候,调度观察者的更新方法。
- 比如有个“天气中心”的具体目标A,专门监听天气变化,而有个显示天气的界面观察者B,B就把自己注册到A里,当A触发天气变化,就调度B的更新方法,并带上自己的上下文。
- 发布&订阅模式:订阅者把自己想订阅的事件注册到调度中心,当该事件触发时候,发布者发布该事件到调度中心(顺带上下文),由调度中心统一调度订阅者注册到调度中心处理代码。
- 比如有个界面实时显示天气,它就订阅天气事件(注册到调度中心,包括处理程序),当天气变化时(定时获取数据),就作为发布者发布天气信息到调度中心,调度中心就调度订阅者的天气处理程序。
- 观察者模式:目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。具体观察者和具体目标继承各自的基类,然后具体观察自己注册到具体目标里。在具体目标发生变化的时候,调度观察者的更新方法。
1 | // 主体,保存状态,状态变化后触发所有观察者对象 |
应用场景:JS事件、JS Promise、JQuery.$CallBack、Vue watch、NodeJS自定义事件,文件流等
迭代器模式
- 顺序访问一个集合
- 使用者无需知道集合的内部结构(封装)
- 提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示
1 | class Iterator { |
状态模式
- 一个对象有状态变化
- 每次状态变化都会触发一个逻辑
- 不能总是用
if...else
来控制
示例:收藏、取关、交通灯
1 | // 交通灯的三色变化 |
到此我们了解了在前端开发中常见的一些设计模式
虽然了解各种设计模式很重要,但同样重要的是不要过度使用他们,在使用设计模式之前,你应该仔细考虑你所处的问题是否符合该设计模式。要了解模式是否符合你的问题,你应该研究设计模式的思想,以及该设计模式的应用。
‘摘抄’不是单纯的“粘贴->复制”,而是眼到,手到,心到的一字一句敲打下来。
博客声明:所有转载的文章、图片仅用于作者本人收藏学习目的,被要求或认为适当时,将标注署名与来源。若不愿某一作品被转用,请及时通知本站,本站将予以及时删除。