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

不知道如何提高代码的可重用性?看看这些设计模式!

时间:2023-03-12 23:55:30 科技观察

大家一定听说过DRY原则。其实就是Don'trepeatyourself(不要重复自己)的意思,就是不要重复写同样的代码,换句话说就是提高代码的复用性。那么什么样的代码有利于可重用性呢?对象可以重复使用。这其实有点像我们关系型数据库的设计原理。数据表和关系表是分开的。数据表是纯数据,与其他表或业务逻辑无关。关系表存储具体的对应关系。当我们需要某个数据的时候,直接读取这个表就可以了,不用担心这个表里面会有其他的业务。还有类似设计的redux。reduxstore包含的是纯数据,不对应具体的业务逻辑。如果业务需要更改数据,则需要发送一个动作。正是因为这种数据非常简单,所以我们可以在任何需要的地方使用它,复用性非常高。因此,我们在设计数据或对象时,应该尽量做到可重用。重复代码少。如果你写的代码重复度很高,说明你的代码还不够抽象。很多时候我们复制代码是因为我们可能需要写一个类似于现有功能的功能,所以我们复制以前的代码并更改两行代码来完成工作。这样虽然实现了功能,但是却产生了很多重复的代码。本文中的几种设计模式就是用来解决这个问题的,提高代码的抽象度,减少重复代码。该模块具有单一功能。这意味着一个模块专注于一个功能,当我们需要做一个大的功能时,我们可以组合多个模块。这就像乐高积木。功能单一的模块就像一小块乐高积木。我们可以用10个小零件来组装一辆小汽车,或者用20个小零件来组装一辆大卡车。但是如果我们的模块本身比较复杂,做成一辆小车,我们就不能用两辆小车组成一辆大货车,复用性会降低。提高复用性的设计模式主要有桥接模式、享元模式、模板方法模式。让我们分别来看一下。桥接模式桥接模式,顾名思义,其实就相当于一座桥,将不同维度的变量桥接在一起,实现功能。假设我们需要实现三个形状(矩形、圆形、三角形),每个形状有三种颜色(红、绿、蓝)。针对这个要求有两种方案。一个方案写了九个方法,每个方法实现了一个Graphics:){}functionblueTriangle(){}虽然上面的代码实现了功能,但是如果我们的需求发生变化,我们要求换一种颜色,那么我们就得再增加三个方法,每个形状一个。这么多方法看起来重复性很强,也就是说他有优化的空间。让我们仔细看看这个要求。我们要绘制的最终图形有两个变量,颜色和形状。这两个变量实际上没有很强的逻辑关系,完全是二维变量。那么我们就可以把这两个变量分开,等我们最后要画图形的时候再把它们桥接起来,就是这样:}functiontriangle(color){//三角形showColor(color);}functionshowColor(color){//显示颜色的方法}//使用时,需要一个红色圆圈letobj=newcircle('red');使用桥接后模式,我们的方法已经从3*3变成了3+1,如果后续添加颜色,我们只需要稍微修改一下showColor方法,让它支持新的颜色。如果我们变量的维度不是2,而是3,这个优势会更加明显。前一种方法需要x*y*z,桥接方式优化为x+y+z,直接指数优化。所以这里桥接模式优化的核心思想是观察重复的代码是否可以拆分成多个维度,如果可以的话,把不同的维度分开,然后在使用的时候桥接这些维度。例子:画笔和蜡笔桥接模式其实我最喜欢的例子是画笔和蜡笔,因为这个例子非常直观,也很容易理解。本例的需求是绘制细线、中线和粗线。每种类型的线需要5种颜色。如果我们用蜡笔画画,我们需要15支蜡笔。如果我们换毛笔画画,我们只需要3支毛笔就可以,每次用不同颜色的墨水,用完换墨水就行了。代码中是这样写的,有点像上面的:color);//用颜色绘制}functionmiddlePen(color){this.color=color;}middlePen.prototype.draw=function(){drawWithColor(this.color);//用颜色绘制}functionbigPen(color){this.color=color;}bigPen.prototype.draw=function(){drawWithColor(this.color);//用颜色color画画}//再来一个颜色类functioncolor(color){this.color=color;}//使用时newmiddlePen(newcolor('red')).draw();//画一条中红线newbigPen(newcolor('green')).draw();//画一条大绿线在上面的例子中,蜡笔不能分开,因为大小和颜色是它们自己的属性。需要的蜡笔数量是两个维度的乘积,也就是15个,如果多一个维度,复杂度会呈指数级增长。.但是画笔大小和颜色这两个维度是分开的,使用的时候可以桥接在一起。只需要三支毛笔和五瓶墨水,复杂度大大降低。上面代码的颜色我新建了一个类,把前面绘制图形的例子中的颜色直接作为参数传入。这样做的目的是为了证明即使是相同的设计模式也可以有不同的实现。使用哪种方案取决于我们的实际需求。如果你想桥接一个简单的变量,比如颜色,你可以把它作为参数传递。如果你想桥接一个复杂的对象,你可能需要一个类。另外,上面代码中的三个笔类看起来非常重复。其实进一步优化可以抽取一个模板,也就是pen的基类。详情见后面的模板方法模式。示例:菜单项本示例的需求是:有多个菜单项,每个菜单项的文字不同,鼠标滑入滑出时文字的颜色也不同。我们一般实现的时候,可能会这样写代码:newmenuItem('menu2');varmenu3=newmenuItem('menu3');//为每个菜单设置鼠标滑入滑出事件menu1.dom.onmouseover=function(){menu1.dom.style.color='red';}menu2.dom.onmouseover=function(){menu1.dom.style1.color='green';}menu3.dom.onmouseover=function(){menu1.dom.style1.color='blue';}menu1.dom.onmouseout=function(){menu1.dom.style1.color='green';}menu2.dom.onmouseout=function(){menu1.dom.style1.color='blue';}menu3.dom.onmouseout=function(){menu1.dom.style1.color='red';}上面的代码看起来很重复。为了去掉这些重复的代码,我们将事件绑定和颜色设置两个维度分开://多个菜单项类接收一个参数colorfunctionmenuItem(word,color){this.dom=document.createElement('div');this.dom.innerHTML=word;this.color=color;//接收color参数作为实例属性}//菜单项类添加绑定事件的实例方法menuItem.prototype.bind=function(){varthat=this;//这里this指向menuItem实例对象this.dom.onmouseover=function(){this.style.color=that.color.colorOver;//注意这里是在事件回调中this表面上指向DOM节点}this.dom.onmouseout=function(){this.style.color=that.color.colorOut;}}//创建另一个类来存储颜色。目前这个类比较简单,以后可以使用需要扩展函数menuColor(colorOver,colorOut){this.colorOver=colorOver;this.colorOut=colorOut;}//现在新建的菜单项可以直接用数组来循环varmenus=[{word:'menu1',colorOver:'red',colorOut:'green'},{word:'menu2',colorOver:'green',colorOut:'blue'},{word:'menu3',colorOver:'blue',colorOut:'red'},]for(vari=0;i0){result=arr.shift()(result);}returnresult;}//现在可以直接使用counter了varcounterIntance=newcounter();counterIntance.before(num=>num+10);//计算前加10counterintance.after(num=>num-5);//计算然后减去5counterIntance.count(2);//2+10+1-5=8这个时候继承没有用了,还是定义首先创建一个基本的操作骨架,然后在这个骨架上展开不同地方需要的特殊操作。总结如果我们的代码中有很多相似的代码块,往往意味着还有进一步优化的空间。如果这些重复的代码块可以拆分成不同的维度,可以尝试桥接模式,先拆分维度,再桥接这些维度使用。如果这些重复代码的某些操作是相同的,但每个操作的对象不同,我们可以考虑使用享元模式,将公共操作提取到方法中,并将私有部分作为参数传入。如果这些重复代码的一些基本操作是相同的,但是在具体的应用中需要更多的功能,我们可以考虑将这些基本操作提取到模板中,然后在模板上留下扩展接口,在需要的时候可以使用这些接口来扩展功能有点类似于继承,但实现不限于继承。我们把重复的部分提取出来,可以用在其他地方。事实上,它提高了代码的可重用性。还是那句话,设计模式没有固定的范式,主要是理解他的思想,代码在不同的地方可以有不同的实现方式。作者:蒋鹏飞链接:https://juejin.im/post/5ecb67846fb9a047b534a346来源:掘金