当前位置: 首页 > Web前端 > HTML

学会这些设计模式,可以让你写出更优雅的代码

时间:2023-04-02 15:39:23 HTML

写代码容易,写优雅代码难。编写易于维护、易于扩展、结构清晰的代码应该是每个开发人员的目标。而学习设计模式,合理使用可以让我们离这个目标更近一步。最近看了一本书《Javascript设计模式与开发实践》。总之,这是一本非常好的书。这里总结了一些我们可以在书中介绍的JavaScript中使用的主要设计模式。设计模式的思想值得反复咀嚼和思考。在以后的业务实施中,应该将这些思路结合起来,合理利用更多的内容。单例模式单例模式确保类只有一个实例并提供全局访问ImplementfunctiongetSingle(fn){letresultreturnfunction(){returnresult||(result=fn。独立封装,可以相互替代。一个基于策略的程序至少由两部分组成,一个是一组策略类,策略类封装了具体的算法,负责具体的计算过程。另一个是环境类,环境类接受客户策略模式的一个使用场景:表单验证,将不同的验证规则封装到一组策略中,避免了多个条件判断语句一句经典的话:Inalanguagewherefunctionsarefirst-类对象,策略模式是隐式的,一个策略是一个变量,其值为一个函数示例:constS=(salary)=>{returnsalary*4}constA=(salary)=>{returnsalary*3}constB=(salary)=>{returnsalary*2}constcalculate=(fun,salary)=>{returnfun(salary)}calculate(S,1000)代理模式代理模式为对象提供替代或占位符控制对其的访问并不直接与本体交互,而是在中间加了一层代理,代理处理一些不需要本体的操作varmyImage=function(){varimgNode=document.createElement('img')文档。body.appendChild(imgNode)返回{setImg(src){imgNode.src=src}}}varproxyImg=function(){varimg=newImage()img.onload=function(){myImage.setSrc(this.src)}return{setImg(src){myImage.setSrc('loading.png')img.src=src}}}代理的意义是单一职责原则的体现。单一职责原则意味着一个函数或类应该只负责一件事。如果一个函数的职责太多,就相当于把这些职责耦合在一起。当一个部分需要改变时Observer和发布-订阅模式Observer和发布-订阅模式使得程序的两部分不必紧耦合在一起,而是通过通知的方式进行通信Observer模式维护一个对象的一系列依赖于它的对象,当对象的状态改变时主动通知这些依赖对象this.observers=[]}add(observer){this.observers.push(observer)}notify(data){for(letobserverofthis.observers){observer.update(data)}}}classObserver{update(){}}观察者模式的缺点是对象必须自己维护一个观察者列表。当对象状态更新时,直接调用其他对象的方法。因此,在使用中,我们一般采用一种变形的方式,即发布订阅模式发布订阅模式这种模式在主体和观察者之间增加了一层管道,使得主体和观察者不直接交互,发布者向管道发布内容,订阅者订阅管道中的内容,目的是避免订阅者和发布者两个类之间存在依赖关系Pubsub{constuctor(){this.pubsub={}this.subId=-1}publish(topic,data){if(!this.pubsub[topic])返回constsubs=this.pubsub[topic]constlen=subs.lengthwhile(len--){subs[len].update(topic,data)}}/***topic{string}*update{function}*/subscribe(topic,update){!this.pubsub[topic]&&(this.pubsub[topic]=[])this.subId++this.pubsub[topic].push({token:this.subId,update})}unsubscribe(token){for(lettopicinthis.pubsub){if(this.pubsub.hasOwnProperty(topic)){constcurrent=this.pubsub[topic]for(leti=0,j=current.length;i{constret=this.apply(this,[...args,()=>{returnfn&&fn.apply(this,args)}])if(ret==='NEXT'){returnfn&&fn.apply(this,args)}returnret}}}/***example*classTest{**test(...args){*alert('test')*return'NEXT'*}**test1(...args){**setTimeout(()=>{*alert('test1')*args.pop()()*})*}**test2(...args){*alert('test2')*}**$onInit(){*constchain=this.test.bind(this)*.chainAfter(this.test1.bind(this))*.chainAfter(this.test2.bind(this))*chain(1,2,3)*}*}**/装饰器模式在不改变原有函数或对象函数的情况下为它们添加新的函数。使用AOP修饰函数if(Function.prototype.before){thrownewError('before方法已经存在')}else{Function.prototype.before=function(beforefn){return()=>{if(beforefn.apply(this,arguments)){this.apply(this,arguments)}}}}if(Function.prototype.after){thrownewError('after方法已经存在')}else{Function.prototype.after=function(afterfn){return()=>{this.apply(this,arguments)afterfn.apply(this,arguments)}}}state该模式允许对象在其内部状态发生变化时改变其行为。该对象似乎修改了它的类。要点:将状态封装成一个单独的函数,将请求委托给当前状态对象。当对象的内部状态发生变化时,会带来不同的行为变化。电灯示例:一个按钮控制电灯的开关,按一次开灯,再按一次关灯。初始实现:classLight{constructor(){this.state='off',this.button=null}init(){//创建按钮节点.....this.button.onClick=()=>{this.btnPressed()}}btnPressed(){if(this.state=='off'){this.state='on}else{this.state='off'}}}这段代码的缺点是不易扩展。添加闪烁状态时,需要修改btnPressed中的代码,使用状态模式重写classLight{constructor(){this.state=FSM.off,this.button=null}init(){//创建按钮节点.....this.button.onClick=()=>{this.state.btnPressed.call(this)}}}constFSM={on:{btnPressed(){//处理this.state=FMS.on}},off:{btnPressed(){//处理this.state=FMS。离开}}}