转载自:https://zhuanlan.zhihu.com/p/115874575
一、常用设计模式
1、单例模式:确保只有一个实例,并提供全局访问。
2、策略模式:定义一些列的算法,把它们一个个封装起来,并且使它们可以相互替换。
3、代理模式:为一个对象提供一个代用品或占位符,以便控制对它的访问。js里虚拟代理(网络请求方面)、缓存代理(数据方面)最常用
4、迭代器模式:提供一种方法,顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。不需要关心对象的内部构造,也可以按顺序访问其中的每个元素。很多语言都有自己内置的迭代器,比如js的Array.prototype.forEach
5、发布-订阅模式:又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态生改变时,所有依赖于它的对象都将得到通知。在js中,一般用事件模型代替它。
var a={} a.b={} a.c=function(key,fn){ if(!this.b[key]){ this.b[key]=[] } this.b[key].push(fn) } a.d=function(){ var key =Array.prototype.shift.call(arguments), fns=this.b[key] console.log(arguments) if(!fns||fns.length===0){ return false; } for(var i=0,fn;fn=fns[i++];){ fn.apply(this,arguments) } } a.c('88',function(pri){ console.log(pri) }) a.c('110',function(pri){ console.log(pri) }) a.d('88',200) a.d('110',300)
6、命令模式:执行某些特定事情的指令。记录信息的清单,就是命令模式中的命令对象。
PS:有时候,需要像某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。这时候就需要命令模式,使得请求发送者和请求接收者能够消除耦合关系。
7、组合模式:使用树形方式创建对象的结构,把相同的操作应用在组合对象和单个对象上。
8、模板方法模式:只需要集成就可以实现,由两部分组成,第一部分是抽象类,第二部分是具体的实现子类。通常在抽象父类中封装了子类的算法框架,包括实现一些公共方法以及封装子类中所有方法的执行顺序。子类通过继承这个抽象类,也继承了整个算法结构,并且可以选择重写父类的方法。
//抽象类 var a=function(){}; a.prototype.b=function(){ console.log('把水煮沸') } a.prototype.c=function(){} a.prototype.d=function(){} a.prototype.e=function(){} a.prototype.init=function(){ this.b(); this.c(); this.d(); this.e(); } //子类 var g=function(){} g.prototype.c=function(){ console.log('用沸水冲咖啡') } g.prototype.d=function(){ console.log('把咖啡倒进杯子') } g.prototype.e=function(){ console.log('加糖和牛奶') } var h=new g() h.init()
这里的a.prototype.init就是模板方法
9、好莱坞原则:即高层组件调用底层组件,模板方法是好莱坞的一个典型使用场景;子类放弃了对自己的控制权,而是改为父类通知子类哪些方法应该在什么时候被调用。作为子类,只负责提供一些设计上的细节。
Ps:发布-订阅模式、回调函数都用到了此原则
10、享元模式:运用共享技术来有效支持大量细粒度的对象。
Ps:
- 内部状态存储与对象内部。
- 内部状态可以被一些对象共享。
- 内部状态独立于具体的场景,通常不会改变。
- 外部状态取决于具体的场景,并根据场景而变化,外部状态不能被共享。
11、对象池:维护一个装在空闲对象的池子,如果需要对象的时候,不是直接new,而是转从对象池里获取。如果对象池里没有空闲对象,则创建一个新的对象,当获取出的对象完成它的职责后,再进入池子等待被下次获取;
12、职责链模式:使多个对象都有机会处理请求,并从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
PS:有多个if-else条件的时候,要去考虑是否可以用职责链模式。
13、中介者模式:解除对象与对象之间得耦合关系。增加一个中介者对象后,所有得相关对象都通过中介者对象来通信,而不是互相引用,所有当一个对象发生改变时,只需要通知中介者对象即可。此模式迎合迪米特法则的一种实现,迪米特也叫做最少知识原则,是指一个对象应该尽可能少地了解另外的对象。
PS:编写思路:1、利用发布-订阅模式2、在中介者对象中开放一些接收消息得接口
14、装饰者模式:给对象动态地增加职责。这种方式并没有真正地改动对象自身,而是将对象放入另一个对象之中,这些对象以一条链的方式进行引用,形成一个聚合对象。
PS:经常用到Function.pototype.after和Function.pototype.before两个函数进行装饰
Function.prototype.before=function(beforefn){ var _self=this;//保存原函数引用 return function(){// 返回包含了原函数和新函数的“代理”函数 beforefn.apply(this,arguments);// 执行新函数,且保证this不被劫持,新函数接受的参数也会被原封不动地传入原函数,新函数在原函数之前执行 return _self.apply(this,arguments);// 执行原函数并返回原函数的执行结果,并且保证this不被劫持 } }
注意:这里的beforefn和原函数_self共用一组参数列表arguments,当我们在beforefn的函数体内改变arguments的时候,_self接收的参数列表自然也会变化,所以经常用于动态地改变原函数的参数
15、状态模式:关键是区分事物内部的状态,事物内部状态的改变往往会带来事物的行为改变。此模式关键是把事物的每种状态都封装成单独的类。
PS:状态模式和策略模式区别:
策略模式的各个策略类之间是平等又平行的,他们之间没有任何联系,所以客户必须熟知这些策略类的作用。以便随时切换算法;而状态模式,状态和状态对应的行为早已被封装好的,状态之间的切换也早被规定完成,“改变行为”这件事发生在状态模式内部。对客户来说,并不需要了解这些细节,这正是状态模式的作用所在。
16、适配器模式:解决两个软件实体的接口不兼容的问题。不考虑接口是怎样实现的,也不考虑将来可能会如何让变化,适配器模式不需要改变已有的接口,就能够使他们协同作用,适配器模式通常只包装一次。
var a={ show:function(){ console.log('a数据源开始渲染') } } var b={ disply:function(){ console.log('b数据源开始渲染') } } //适配器c var c={ show:function(){ return b.disply(); } } var render=function(fn){ fn.show() } render(a) render(c)
17、外观模式:在JS中不常用。主要是为子系统中的一组接口提供一个一致的界面,定义了一个高层的接口,这个接口使子系统更加容易使用。在C++或者JAVA中指的是一组类的集合,这些类相互协作可以组成系统中一个相对独立的部分。但在JS中,这个子系统至少应该指的是一组函数的集合。
var A=function(){ a1() a2() }
今天的文章前端常用的设计模式有哪些_前端面试官常问的问题分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/49073.html