当前位置: 首页 > 科技观察

Web开发应了解的5种设计模式

时间:2023-03-11 22:38:27 科技观察

Web开发应该了解的5种设计模式转载本文请联系前端进阶路径公众号。什么是设计模式?设计模式是针对软件设计和开发过程中反复出现的某一类问题的通用解决方案。设计模式更多的是指导思想和方法论,而不是现成的代码。当然,每种设计模式在每种语言中都有特定的实现。学习设计模式更多的是理解各种模式的内在思想和解决方案。毕竟这是无数前人经验总结出来的最佳实践,代码实现是加深理解的辅助手段。设计模式用于可重用的代码,使代码更容易被他人理解,并保证代码的可靠性。在这篇文章中,我将介绍JavaScript中常见的五种设计模式的实际使用场景:那个例子。实现方法是判断对象是否有实例。如果已经存在,则不会再次创建。使用场景只适用于业务场景中的一个实例,如弹窗、购物车等。单例模式分为懒惰和饥饿。:惰性风格letShopCar=(function(){letinstance;functioninit(){/*在这里定义单例代码*/return{buy(good){this.goods.push(good);},goods:[],};}return{getInstance:function(){if(!instance){instance=init();}returninstance;},};})();letcar1=ShopCar.getInstance();letcar2=ShopCar.getInstance();car1.buy('orange');car2.buy('apple');console.log(car1.goods);//['orange','apple']console.log(car1===car2);//真饿了么中国风varShopCar=(function(){varinstance=init();functioninit(){/*这里定义了单例代码*/return{buy(good){this.goods.push(good);},goods:[],};}return{getInstance:function(){returninstance;},};})();letcar1=ShopCar.getInstance();letcar2=ShopCar.getInstance();car1.buy('橙色');car2.buy('apple');//['orange','apple']console.log(car1.goods);console.log(car1===car2);//加载类时真正的懒惰风格,不创建实例,类加载速度快,但运行时获取对象速度慢;饿了么中文风格是在类加载的时候初始化的,所以类加载慢,但是对象获取速度快策略模式定义策略模式定义1一系列的算法,封装了各个算法,让它们可以相互替代。实现方法定义了一组可变的策略类来封装具体的算法,定义了一组常量环境类将请求委托给某个策略类。使用场景适用于需要判断多个条件,甚至是复杂条件嵌套的业务场景,可以使用策略模式来提高代码的可维护性和可读性。例如支付和博客权限验证的实现示例//定义几个策略类varPaymentMethodStrategy={BankAccount:function(money){returnmoney>50?money*0.7:money;},CreditCard:function(money){returnmoney*0.8;},Alipay:function(money){returnmoney;},};/*环境类*/varuserPay=function(selectedStrategy,money){returnPaymentMethodStrategy[selectedStrategy](money);};console.log('银行卡支付价格为:'+userPay('BankAccount',100));//70console.log('支付宝支付价格为:'+userPay('Alipay',100));//100console.log('信用卡支付价格为:'+userPay('CreditCard',100));//80观察者模式定义观察者模式是对象的行为模式,定义了对象之间一对多的依赖关系,即多个观察者和一个被观察者当被观察对象发生变化时,所有的观察者对象都会得到通知,它们会执行相应的操作。实现方法定义了一组可变的策略类来封装具体的算法,定义了一组常量环境类将请求委托给某个策略类。使用场景适用于业务场景。当一个对象的状态发生变化时,需要自动通知其他人。关联对象,自动刷新对象状态,或者执行对应对象的方法。比如你是老师,需要通知班里的家长,你可以创建一个群(列表)。每次通知一个事件,只需要循环遍历这个列表(群发)即可,不用关心这个列表中有谁。实现实例//创建一个group,保存通知,通知变化后通知每个parent(触发所有观察者对象)classGroup{constructor(){this.message='nonotification';this.parents=[];}getMessage(){returnthis.message;}setMassage(message){this.message=message;this.notifyAllObservers();}notifyAllObservers(){this.parents.forEach((parent)=>{parent.update();});}attach(parent){this.parents.push(parent);}}//观察者,每个父类Parent{constructor(name,group){this.name=name;this.group=group;this.group.attach(this);}update(){console.log(`${this.name}收到通知:${this.group.getMessage()}`);}}letgroup=newGroup();lett1=newParent('李妈妈',group);lett2=newParent('王爸爸',group);lett3=newParent('张爷爷',group);group.setMassage('开家长会');group.setMassage('开运动会');/*李妈妈收到通知:召开家长会王爸爸收到通知:开家长会张爷爷收到通知:开运动会*/publish-subscribemodedefinitionpublish-subscribemode指的是对象(Subscriber)希望通过自定义事件订阅主题接收基于某个主题的通知,发布事件的对象(Publisher)发布主题事件方法通知每个订阅该主题的Subscriber对象。实现constpubSub={list:{},subscribe(key,fn){//subscribeif(!this.list[key]){this.list[key]=[];}this.list[key].push(fn);},publish(){//发布constarg=arguments;constkey=Array.prototype.shift.call(arg);constfns=this.list[key];if(!fns||fns.length<=0)returnfalse;for(vari=0,len=fns.length;i{console.log('yournameis'+name);});pubSub.subscribe('sex',(sex)=>{console.log('yoursexis'+sex);});//发布pubSub.publish('name','ttsy1');//yournameisttsy1pubSub.publish('sex','male');//订阅上面yoursexismale的代码是根据name和sextopic自定义事件,publication是通过name和sextopic并传入自定义事件的参数,最终触发特定topic的自定义事件.可以通过unSubscribe方法取消对特定主题的订阅。pubSub.subscribe('name',(name)=>{console.log('yournameis'+name);});pubSub.subscribe('sex',(sex)=>{console.log('yoursexis'+sex);});pubSub.unSubscribe('name');pubSub.publish('name','ttsy1');//本主题取消订阅pubSub.publish('sex','male');//yoursexismale观察者模式VS发布订阅模式:观察者模式和发布订阅模式都定义了一对多的依赖关系,当相关状态发生变化时,进行相应的更新。不同的是,在观察者模式下,一系列依赖于Subject对象的Observer对象在收到通知后只能执行同一个具体的更新方法,而在发布订阅模式下,可以根据不同的主题事件进行不同的定制.相对来说,发布-订阅模型比观察者模型更灵活。装饰器模式定义在不改变原有结构和功能的情况下,动态装饰一些适用于特殊场景的方法或属性,即增加一些新的功能来增强其某些能力。实现方法定义一组可变策略类封装具体算法,定义一组不变的环境类,将请求委托给某个策略类,使用场景原有方法不变,在原有方法上挂载其他方法满足现有需求;函数的解耦将函数拆分成多个可复用的函数,然后将拆分后的函数挂载到一个函数上,达到同样的效果但增强了复用性。如多孔套接字,机车改装实现示例:constMan=function(){this.run=function(){console.log('running');};};constDecorator=function(old){this.oldAbility=old。run;this.fly=function(){console.log('有飞行能力');};this.newAbility=function(){this.oldAbility();this.fly();};};constman=newMan();constsuperMan=newDecorator(man);superMan.fly();//具有飞行能力的代理模式定义代理模式为某个对象提供代理对象,代理对象控制对原对象的引用.通俗地说,代理模式就是我们生活中常见的中介。实现方法中定义了一个delegator和一个proxy,需要委托的事情都在proxy中完成。在某些情况下,客户类不想或不能直接引用委托对象,代理类对象可以位于客户类和委托对象之间。起到中介作用。代理可以帮助客户端过滤掉一些请求,并延迟创建一些昂贵的对象,直到真正需要它们为止。中介购车、代购、课代表收老师作业示例:classLetter{constructor(name){this.name=name;}}//暗恋小明letXiaoMing={name:'Xiaoming',sendLetter(target){目标。receiveLetter(this.name);},};//代理小花letxiaoHua={receiveLetter(customer){//当然是等小红心情好的时候发情书,之后再创建情书发送情书XiaoHong.listenGoodMood(()=>{XiaoHong.receiveLetter(newLetter(customer+'情书'));});},};//喜欢的对象小红letXiaoHong={name:'小红',receiveLetter(letter){console.log(this.name+'received:'+letter.name);},listenGoodMood(fn){setTimeout(()=>{fn();},1000);},};小明。sendLetter(xiaoHua);//小红收到:小明的情书Proxy是ES6提供的代理,具体出现在proxy的角色中。Vue3.0的响应式数据部分摒弃了Object.defineProperty,改用Proxy。varproxy=newProxy(目标,处理程序);现在用Proxy来模拟另一个场景:为了保护挂科的学生,课代表在拿到全班的成绩单后,才会公布合格者的成绩。对考试成绩有疑问的考生,经复议后,新成绩比原成绩提高10分后,有权更新成绩。,name){if(scoreList[name]>69){console.log('输出分数');returnscoreList[name];}else{console.log('失败分数无法公布');}},set:function(scoreList,name,val){if(val-scoreList[name]>10){console.log('修改分数');scoreList[name]=val;}else{console.log('不能修改分数');}},});yyProxy['wang']=98;//无法修改结果yyProxy['li']=80;//修改结果总结我以前觉得设计模式很疯狂,离软件开发指南很远。然后我发现我一直在使用它们!我介绍的一些模式在许多应用程序中都有使用。但归根结底,它们只是理论。作为开发者,是否使用取决于使用后是否让代码逻辑更容易实现和维护。