看看這篇針對Java開發(fā)人員的SOLID規(guī)劃準(zhǔn)則簡介。
當(dāng)你剛觸摸軟件工程時,這些原理和規(guī)劃形式不容易了解或習(xí)氣。咱們都遇到了問題,很難了解SOLID+DP的思維,乃至很難正確施行它們。確實,“為什么要SOLID?”的整個概念,以及怎么施行規(guī)劃形式,這需求時刻和許多實踐。
我可以說實話,關(guān)于SOLID規(guī)劃形式以及TDD等其他領(lǐng)域,從本質(zhì)上講,它們很難教。很難以正確的辦法將所有這些知識和信息傳授給年輕人。
讓SOLID變得容易
在本文中,我將以盡可能簡略的術(shù)語,經(jīng)過簡略易懂的示例來教授SOLID的每個字母。
SOLID的“S”
S代表SRP(單一責(zé)任準(zhǔn)則)?;舅季S是應(yīng)用關(guān)注點分離,這意味著你應(yīng)測驗將關(guān)注點分離到不同的類中。一堂課應(yīng)該專注于單個問題,邏輯或單個領(lǐng)域。當(dāng)域,標(biāo)準(zhǔn)或邏輯發(fā)生變化時,它只影響一個類。
施行SRP之前
下面,咱們違背了SRP。VehicleServiceResource類完成了兩種不同的辦法,并以兩種人物結(jié)束。如咱們所見,該類具有兩個標(biāo)記其用法的注釋。
一種是向客戶端揭露和供給HTTP終結(jié)點服務(wù)的人物。
第二個是車輛服務(wù)的人物,該服務(wù)從存儲getVehicles()中獲取車輛并核算總值calculateTotalValue():
1@EndPoint(“vehicles”)2@Service3publicclassVehicleServiceResource{4…5@GET6publicListgetVehicles(){7}8publicdoublecalculateTotalValue(){}9…10}
完成SRP的簡略目標(biāo)是將VehicleServiceResource分為兩個不同的類:一個用于端點,另一個用于服務(wù)。
SRP施行后
咱們要做的是獲取VehicleServiceResource類,并將其分為兩個不同的類。
VehicleResource類僅具有一項和一項工作。為了向客戶端揭露HTTP資源工具并向其供給服務(wù),所有與業(yè)務(wù)邏輯相關(guān)的辦法均導(dǎo)致VehicleService類。
1@EndPoint(“vehicles”)2publicclassVehicleResource{3@Service4privateVehicleServiceservice;5@GET6publicListgetVehicles(){7returnthis.service.getVehicles();8}9…10}
咱們創(chuàng)建了一個名為VehicleService的新類。此類完成所有與車輛有關(guān)的邏輯。
1@Service2publicclassVehicleService{3…4publicListgetVehciles(){}5publicdoublecalculateTotalValue(){}6…7}
SOLID的“O”
O代表OCP(開閉原理)。開閉準(zhǔn)則指出:
“…軟件實體(例如模塊,類,功用等)應(yīng)打開以進(jìn)行擴(kuò)展,但應(yīng)封閉以進(jìn)行修正。”
術(shù)語“敞開擴(kuò)展”是指咱們可以在代碼中擴(kuò)展并包含額外的案例/功用,而不會更改或影響咱們現(xiàn)有的完成。
術(shù)語“封閉以進(jìn)行修正”表示在增加了附加功用之后,咱們不該修正現(xiàn)有的完成。
一個簡略的違背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}
當(dāng)咱們要包含一種新式車輛“貨車”時,就會違背OCP。需求對calculateVehicle辦法進(jìn)行重構(gòu)和代碼修正。
解決
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}
這樣,經(jīng)過運(yùn)用一種承受IVehicle的辦法,今后在每次增加新式車輛時都無需進(jìn)行重構(gòu)/代碼修正。
典范程式碼
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盡可能簡略,并掃除許多詳細(xì)的細(xì)節(jié),由于LSP又是另一天的評論和爭辯。
LSP指出,當(dāng)咱們用任何子類型替換父類型時,該軟件不該改動期望的成果。
LSP不僅僅是一個規(guī)劃形式,更是一個問題界說,而咱們可以做的是避免不良影響。
為了更清楚地說明這一點,咱們將檢查以下簡略示例:
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目標(biāo)的類型并設(shè)置寬度和高度。這是違規(guī)的,由于行為發(fā)生了變化,并且在傳遞方形引證時咱們的數(shù)據(jù)不一致。
有許多解決方案。其中一些將應(yīng)用“敞開式封閉準(zhǔn)則”和經(jīng)過“合同”形式進(jìn)行規(guī)劃。
還有許多其他解決LSP違規(guī)問題的辦法,但是在此不做解說,由于它不在本文評論范圍之內(nèi)。
SOLID的“I”
I代表ISP(接口阻隔原理)。接口阻隔準(zhǔn)則是由RobertC.Martin在為Xerox咨詢時界說的。他將其界說為:
“不該強(qiáng)迫客戶依靠他們不運(yùn)用的接口?!?br />
ISP指出,咱們應(yīng)該將接口拆分為更小,更詳細(xì)的接口。
以下是代表兩個不同人物的界面示例。一個人物是處理打開和封閉之類的銜接,另一個人物是發(fā)送和接收數(shù)據(jù)。
1publicinterfaceConnection{2voidopen();3voidclose();4byte[]receive();5voidsend(byte[]data);6}
在應(yīng)用ISP之后,咱們得到了兩個不同的接口,每個接口代表一個切當(dāng)?shù)娜宋铩?br />
1publicinterfaceChannel{2byte[]receive();3voidsend(byte[]data);4}5publicinterfaceConnection{6voidopen();7voidclose();8}
SOLID的“D”
D代表DIP(依靠性反轉(zhuǎn)原理)。DIP聲明咱們應(yīng)該依靠抽象(接口和抽象類),而不是詳細(xì)的完成(類)。
接下來是違背DIP。咱們有一個Emailer類,詳細(xì)取決于直接的SpellChecker類:
1publicclassEmailer{2privateSpellCheckerspellChecker;3publicEmailer(SpellCheckersc){4this.spellChecker=sc;5}6publicvoidcheckEmail(){7this.spellChecker.check();8}9}
Spellchecker類:
1publicclassSpellChecker{2publicvoidcheck()throwsSpellFormatException{3}4}
現(xiàn)在可能可以運(yùn)用,但是過了一瞬間,咱們要包含兩種不同的SpellChecker完成。咱們有默認(rèn)的SpellChecker和新greekspellchecker。
在當(dāng)前的完成中,需求重構(gòu),由于Emailer類僅運(yùn)用SpellChecker類。
一個簡略的解決方案是為不同的SpellChecker創(chuàng)建要完成的接口。
1//Theinterfacetobeimplementedbyanynewspellchecker.2publicinterfaceISpellChecker{3voidcheck()throwsSpellFormatException;4}
現(xiàn)在,Emailer類在結(jié)構(gòu)函數(shù)上僅承受ISpellChecker引證。下面,咱們將Emailer類更改為不關(guān)心/不依靠于完成(詳細(xì)的類),而是依靠于接口(ISpellChecker)
1publicclassEmailer{2privateISpellCheckerspellChecker;3publicEmailer(ISpellCheckersc){4this.spellChecker=sc;5}6publicvoidcheckEmail(){7this.spellChecker.check();8}9}
咱們?yōu)镮SpellChecker供給了許多完成:
1publicclassSpellCheckerimplementsISpellChecker{2@Override3publicvoidcheck()throwsSpellFormatException{4}5}6publicclassGreekSpellCheckerimplementsISpellChecker{7@Override8publicvoidcheck()throwsSpellFormatException{9}10}
這是另一個代碼示例。不管完成是什么,咱們都將ISpellChecker類型傳遞給Emailer結(jié)構(gòu)函數(shù)。
1publicstaticclassMain{2publicstaticvoidmain(String[]a){3ISpellCheckerdefaultChecker=newSpellChecker();4ISpellCheckergreekChecker=newGreekSpellChecker();5newEmailer(defaultChecker).checkEmail();6newEmailer(greekChecker).checkEmail();7}8}
廣州天河區(qū)珠江新城富力盈力大廈北塔2706
020-38013166(網(wǎng)站咨詢專線)
400-001-5281 (售后服務(wù)熱線)
深圳市坂田十二橡樹莊園F1-7棟
Site/ http://www.szciya.com
E-mail/ itciya@vip.163.com
品牌服務(wù)專線:400-001-5281
長沙市天心區(qū)芙蓉中路三段398號新時空大廈5樓
聯(lián)系電話/ (+86 0731)88282200
品牌服務(wù)專線/ 400-966-8830
旗下運(yùn)營網(wǎng)站:
Copyright ? 2016 廣州思洋文化傳播有限公司,保留所有權(quán)利。 粵ICP備09033321號