志在指尖
用双手敲打未来

适用于Java开发人员的SOLID规划原则简介

看看这篇针对Java开发人员的SOLID规划准则简介。
当你刚触摸软件工程时,这些原理和规划形式不容易了解或习气。咱们都遇到了问题,很难了解SOLID+DP的思维,乃至很难正确施行它们。确实,“为什么要SOLID?”的整个概念,以及怎么施行规划形式,这需求时刻和许多实践。
我可以说实话,关于SOLID规划形式以及TDD等其他领域,从本质上讲,它们很难教。很难以正确的办法将所有这些知识和信息传授给年轻人。
让SOLID变得容易
在本文中,我将以尽可能简略的术语,经过简略易懂的示例来教授SOLID的每个字母。
SOLID的“S”
S代表SRP(单一责任准则)。基本思维是应用关注点分离,这意味着你应测验将关注点分离到不同的类中。一堂课应该专注于单个问题,逻辑或单个领域。当域,标准或逻辑发生变化时,它只影响一个类。java手写多级缓存
施行SRP之前
下面,咱们违背了SRP。VehicleServiceResource类完成了两种不同的办法,并以两种人物结束。如咱们所见,该类具有两个标记其用法的注释。
一种是向客户端揭露和供给HTTP终结点服务的人物。
第二个是车辆服务的人物,该服务从存储getVehicles()中获取车辆并核算总值calculateTotalValue():
1@EndPoint(“vehicles”)2@Service3publicclassVehicleServiceResource{4…5@GET6publicListgetVehicles(){7}8publicdoublecalculateTotalValue(){}9…10}
完成SRP的简略目标是将VehicleServiceResource分为两个不同的类:一个用于端点,另一个用于服务。
SRP施行后
咱们要做的是获取VehicleServiceResource类,并将其分为两个不同的类。
VehicleResource类仅具有一项和一项工作。为了向客户端揭露HTTP资源工具并向其供给服务,所有与业务逻辑相关的办法均导致VehicleService类。
1@EndPoint(“vehicles”)2publicclassVehicleResource{3@Service4privateVehicleServiceservice;5@GET6publicListgetVehicles(){7returnthis.service.getVehicles();8}9…10}
咱们创建了一个名为VehicleService的新类。此类完成所有与车辆有关的逻辑。
1@Service2publicclassVehicleService{3…4publicListgetVehciles(){}5publicdoublecalculateTotalValue(){}6…7}
SOLID的“O”
O代表OCP(开闭原理)。开闭准则指出:
“…软件实体(例如模块,类,功用等)应打开以进行扩展,但应封闭以进行修正。”
术语“敞开扩展”是指咱们可以在代码中扩展并包含额外的案例/功用,而不会更改或影响咱们现有的完成。
术语“封闭以进行修正”表示在增加了附加功用之后,咱们不该修正现有的完成。
一个简略的违背OCP的行为:
1publicclassVehicleValueCalculator{2//letsassumeasimplemethodtocalculatethetotalvalueofavehicle3//withextracostdependingthetype.4publicdoublecalculateVehicle(Vehiclev){5doublevalue=0;6if(vinstanceofCar){7value=v.getValue()+2.0;8}elseif(vinstanceofMotorBike){9value=v.getValue()+0.4;10}11returnvalue;12}13}
当咱们要包含一种新式车辆“货车”时,就会违背OCP。需求对calculateVehicle办法进行重构和代码修正。
解决
1publicinterfaceIVehicle{2doublecalculateVehicle();3}4publicclassCarimplementsIVehicle{5@Override6publicdoublecalculateVehicle(){7returnthis.getValue()+2.0;8}9}10publicclassMotorBikeimplementsIVehicle{11@Override12publicdoublecalculateVehicle(){13returnthis.getValue()+0.4;14}15}
咱们的新货车
1publicclassTruckimplementsIVehicle{2@Override3publicdoublecalculateVehicle(){4returnthis.getValue()+3.4;5}6}
这样,经过运用一种承受IVehicle的办法,今后在每次增加新式车辆时都无需进行重构/代码修正。
典范程式码
1publicclassMain{2publicstaticvoidmain(String[]args){3IVehiclecar=newCar();4IVhecilemotorBike=newMotorBike();5//newaddition6IVheciletruck=newTruck();7doublecarValue=getVehicleValue(car);8doublemotorBikeValue=getVehicleValue(motorBike);9doubletruckValue=getVehicleValue(truck);10}11publicdoublegetVehicleValue(IVehiclev){12returnv.calculateVehicle();13}14}
SOLID的“L”
L代表LSP(Liskov替代原理):
为了使这篇文章成为SOLID的介绍,而不会引起混淆,我将测验使LSP尽可能简略,并扫除许多详细的细节,由于LSP又是另一天的评论和争辩。
LSP指出,当咱们用任何子类型替换父类型时,该软件不该改动期望的成果。
LSP不仅仅是一个规划形式,更是一个问题界说,而咱们可以做的是避免不良影响。
为了更清楚地说明这一点,咱们将检查以下简略示例:
1/**2*TheBaseRectangleclass3*Thisclassdefinesthestructureandpropertiesofalltypesofrectangles4*/5publicclassRectangle{6privateintwidth;7privateintheight;8publicRectangle(){}9publicRectangle(intw,inth){10this.width=w;11this.height=h;12}13publicintgetWidth(){14returnwidth;15}16publicvoidsetWidth(intwidth){17this.width=width;18}19publicintgetHeight(){20returnheight;21}22publicvoidsetHeight(intheight){23this.height=height;24}25publicintgetArea(){26returnthis.height*this.width;27}28/**29*LSPviolationiscaseofaSquarereference.30*/31publicfinalstaticvoidsetDimensions(Rectangler,intw,inth){32r.setWidth(w);33r.setHeight(h);34//assertr.getArea()==w*h35}36}
1/**2*ASpecialkindofRectangle3*/4publicclassSquareextendsRectangle{5@Override6publicvoidsetHeight(inth){7super.setHeight(h);8super.setWidth(h);9}10@Override11publicvoidsetWidth(intw){12super.setWidth(w);13super.setHeight(w);14}15}
在议论LSP时,咱们在Rectangle类中有setDimensions办法,该办法承受Rectangle目标的类型并设置宽度和高度。这是违规的,由于行为发生了变化,并且在传递方形引证时咱们的数据不一致。
有许多解决方案。其中一些将应用“敞开式封闭准则”和经过“合同”形式进行规划。
还有许多其他解决LSP违规问题的办法,但是在此不做解说,由于它不在本文评论范围之内。
SOLID的“I”
I代表ISP(接口阻隔原理)。接口阻隔准则是由RobertC.Martin在为Xerox咨询时界说的。他将其界说为:
“不该强迫客户依靠他们不运用的接口。”
ISP指出,咱们应该将接口拆分为更小,更详细的接口。
以下是代表两个不同人物的界面示例。一个人物是处理打开和封闭之类的衔接,另一个人物是发送和接收数据。
1publicinterfaceConnection{2voidopen();3voidclose();4byte[]receive();5voidsend(byte[]data);6}
在应用ISP之后,咱们得到了两个不同的接口,每个接口代表一个切当的人物。
1publicinterfaceChannel{2byte[]receive();3voidsend(byte[]data);4}5publicinterfaceConnection{6voidopen();7voidclose();8}
SOLID的“D”
D代表DIP(依靠性反转原理)。DIP声明咱们应该依靠抽象(接口和抽象类),而不是详细的完成(类)。
接下来是违背DIP。咱们有一个Emailer类,详细取决于直接的SpellChecker类:
1publicclassEmailer{2privateSpellCheckerspellChecker;3publicEmailer(SpellCheckersc){4this.spellChecker=sc;5}6publicvoidcheckEmail(){7this.spellChecker.check();8}9}
Spellchecker类:
1publicclassSpellChecker{2publicvoidcheck()throwsSpellFormatException{3}4}
现在可能可以运用,但是过了一瞬间,咱们要包含两种不同的SpellChecker完成。咱们有默认的SpellChecker和新greekspellchecker。
在当前的完成中,需求重构,由于Emailer类仅运用SpellChecker类。
一个简略的解决方案是为不同的SpellChecker创建要完成的接口。
1//Theinterfacetobeimplementedbyanynewspellchecker.2publicinterfaceISpellChecker{3voidcheck()throwsSpellFormatException;4}
现在,Emailer类在结构函数上仅承受ISpellChecker引证。下面,咱们将Emailer类更改为不关心/不依靠于完成(详细的类),而是依靠于接口(ISpellChecker)
1publicclassEmailer{2privateISpellCheckerspellChecker;3publicEmailer(ISpellCheckersc){4this.spellChecker=sc;5}6publicvoidcheckEmail(){7this.spellChecker.check();8}9}
咱们为ISpellChecker供给了许多完成:
1publicclassSpellCheckerimplementsISpellChecker{2@Override3publicvoidcheck()throwsSpellFormatException{4}5}6publicclassGreekSpellCheckerimplementsISpellChecker{7@Override8publicvoidcheck()throwsSpellFormatException{9}10}
这是另一个代码示例。不管完成是什么,咱们都将ISpellChecker类型传递给Emailer结构函数。
1publicstaticclassMain{2publicstaticvoidmain(String[]a){3ISpellCheckerdefaultChecker=newSpellChecker();4ISpellCheckergreekChecker=newGreekSpellChecker();5newEmailer(defaultChecker).checkEmail();6newEmailer(greekChecker).checkEmail();7}8}

未经允许不得转载:IT技术网站 » 适用于Java开发人员的SOLID规划原则简介
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

志在指尖 用双手敲打未来

登录/注册IT技术大全

热门IT技术

C#基础入门   SQL server数据库   系统SEO学习教程   WordPress小技巧   WordPress插件   脚本与源码下载