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

JavaScript中的SOLID原则(二):“O”代表什么?

时间:2023-03-27 13:17:39 JavaScript

JavaScript中的SOLID原则:“S”代表什么?您可能知道一些设计原则或设计模式。本文主要逐步讲解SOLID原理:没有使用SOLID写的代码如何,有哪些问题?应该使用SOLID中的哪个原则?我们应该如何使用SOLID修改代码?相信对比和身临其境的例子会让你更容易理解SOLID原则以及如何将其应用到代码实践中。这是SOLID的第二篇翻译文章(共有五篇原创文章),作者为serhiirubets,欢迎继续关注。在本文中,我们将讨论什么是SOLID原则,为什么要使用它们以及如何在JavaScript中使用它们。什么是SOLIDSOLID是RobertC.Martin的前五个面向对象设计原则的首字母缩写。这些原则的目的是使您的代码和架构更具可读性、可维护性和灵活性。开闭原则(Open-ClosedPrinciple)O——开闭原则。实体(类、模块、方法、文件等)应该对扩展开放,对修改关闭。从定义上很难理解,我们来看几个例子:假设:我们有几个不同的形状,圆形,方向,三角形,我们需要计算它们的面积之和。如何解决?没什么难的,让我们为每个形状创建一个类,每个形状都有不同的字段:大小、高度、宽度、半径和类型字段。在计算每个形状的面积时,我们使用类型字段来区分。类Square{构造函数(大小){this.size=size;this.type='square';}}classCircle{constructor(radius){this.radius=radius;this.type='圆圈';}}classRect{constructor(width,height){this.width=widththis.height=height;this.type='rect';}}让我们创建另一个函数来计算面积。functiongetTotalAreas(shapes){returnshapes.reduce((total,shape)=>{if(shape.type=='square'){total+=shape.size*shape.size;}elseif(shape.type='circle'){total+=Math.PI*shape.radius;}elseif(shape.type=='rect'){total+=shape.width*shape.height;}returntotal;},0);}getTotalAreas([newSquare(5),newCircle(4),newRect(7,14)]);看起来好像没什么问题,但是想象一下如果我们要添加另外一个形状(原型,椭圆,菱形),我们该怎么办呢?我们需要为它们中的每一个创建一个新类,定义类型并在getTotalAreas中添加新的if/else。注:O——开闭原则。我们再重复一遍:这个原则的意思是:实体(类、模块、方法等)应该对扩展开放,对修改关闭。在getTotalAreas中,每次添加新形状时都需要对其进行修改。这不遵循开闭原则,我们需要做哪些调整呢?我们需要在每个类中创建getArea方法(不再需要类型字段,它已被删除)。类Square{构造函数(大小){this.size=size;}getArea(){返回this.size*this.size;}}classCircle{constructor(radius){this.radius=radius;}getArea(){返回Math.PI*(this.radius*this.radius);}}classRect{constructor(width,height){this.width=width;this.height=高度;}getArea(){返回this.width*this.高度;}}functiongetTotalAreas(shapes){返回形状。reduce((total,shape)=>{returntotal+shape.getArea();},0)}getTotalAreas([newSquare(5),newCircle(4),newRect(7,14)]);既然已经遵循了开闭原则,那么当我们要添加另外一个形状的时候,比如三角形,我们就创建一个Triangle类(对扩展开放),定义一个getArea方法,仅此而已。我们不需要修改getTotalAreas方法(修改关闭),只需要在调用getTotalAreas的时候在其数组中添加一个参数即可。我们看一个更实际的例子,假设客户端收到一个指定格式的错误验证信息:containnumbers'],email:['emailfieldisrequired'],phone:['Userwithprovidedphoneexist']}}假设服务器使用不同的服务进行验证,它可能是我们自己的服务,或者可能是一个外部服务返回不同格式的错误。让我们使用尽可能简单的示例来模拟错误:consterrorFromFacebook='Badcredentials';consterrorFromTwitter=['错误凭证'];consterrorFromGoogle={error:'Badcredentials'}functionrequestToFacebook(){return{type:'facebook',error:errorFromFacebook}}functionrequestToTwitter(){return{type:'twitter',error:errorFromTwitter}}functionrequestToGoogle(){return{type:'google',error:errorFromGoogle}}让我们把error转换成客户端要求的格式:functiongetErrors(){consterrorsList=[requestToFacebook(),requestToTwitter(),requestToGoogle()];consterrors=errorsList.reduce((res,error)=>{if(error.type=='facebook'){res.facebookUser=[error.error]}if(error.type=='twitter'){res.twitterUser=error.error;}if(error.type=='google'){res.googleUser=[error.error];}returnres;},[]);返回{错误};}console.log(getErrors());我们得到了客户所期望的:{errors:{facebookUser:['Badcredentials'],twitterUser:['Badcredentials'],googleUser:['Badcredentials']}}但是,它仍然是同样的问题,我们没有遵循开闭原则,当我们需要从外部服务添加新的验证时,我们需要修改getErrors方法并添加新的if/else逻辑如何解决这个问题呢?一个可行的方案是:我们可以创建一些通用的错误验证类,并在其中定义一些通用的逻辑。然后我们可以为每个错误(FaceBookValidationError、GoogleValidationError)创建我们自己的类。在每个类中,我们可以指定方法,如getErrors或TransformErrors,每个validationError类都应遵循此规则。consterrorFromFacebook='Badcredentials';consterrorFromTwitter=['Badcredentials'];consterrorFromGoogle={error:'Badcredentials'}classValidationError{constructor(error){this.error=error;}getErrors(){}}classFacebookValidationErrorextendsValidationError{getErrors(){return{key:'facebookUser',text:[this.error]};}}classTwitterValidationErrorextendsValidationError{getErrors(){return{key:'twitterUser',text:this.error}}}classGoogleValidationErrorextendsValidationError{getErrors(){return{key:'googleUser',text:[this.error.error]}}}我们在Mock的函数中使用这个错误验证类,修改getErrors函数:functionrequestToFacebook(){returnnewFacebookValidationError(errorFromFacebook)}functionrequestToTwitter(){returnnewTwitterValidationError(errorFromTwitter)}functionrequestToGoogle(){返回新的GoogleValidationError(errorFromGoogle)}functiongetErrors(errorsList){consterrors=errorsList.reduce((res,item)=>{consterror=item.getErrors();res[error.key]=error.textreturnres;},{});返回{errors}}console.log(getErrors([requestToFacebook(),requestToTwitter(),requestToGoogle()]));可以看到getErrors函数接收errorList作为参数而不是在函数中硬编码操作结果是一样的,但是我们遵循开闭原则,在添加错误的时候:我们可以为创建一个新的验证类这个错误并指定了getErrors方法(对扩展开放),getErrors可以帮我们把对外服务返回的信息转换成我们需要的格式。我们在一般的getErrors方法中调用error类的getErrors,不做其他修改(关闭修改)。欢迎关注微信公众号《混沌前端》推荐阅读:基于TypeScript看懂程序设计的SOLID原理clean-code-javascript:SOLID