重构一个功能块的总结
因?yàn)長(zhǎng)eader不建議占用上班時(shí)間搞這個(gè),基本上都是加班搞的
在做這個(gè)事的過(guò)程中,對(duì)IntelliJ idea更加熟悉,回顧下Mocikitto中spy,mock,verify,when的使用,這次重構(gòu)基本上是小步快走,層層分離
IntelliiJ idea:
重構(gòu)手法:如果想把一個(gè)方法移動(dòng)到另一個(gè)class中,可以通過(guò)method增加一個(gè)Class類型的參數(shù),然后將光標(biāo)放在方法名的任何字符上【若選中方法名,則F6會(huì)失效】,按F6,在彈出的對(duì)話框中選擇預(yù)期的Class【因?yàn)檫@個(gè)方法的參數(shù)是其它類型的對(duì)象】
更改方法的參數(shù)個(gè)數(shù)時(shí),可以會(huì)調(diào)用處更改,從上往下進(jìn)行,或按Ctrl+F6在調(diào)用的GUI界面操作。IntelliJ Idea的自動(dòng)操作往往留一些尾巴,譬如,刪除一個(gè)構(gòu)造函數(shù)的一個(gè)參數(shù),參數(shù)賦值的字段和構(gòu)造中賦值語(yǔ)句不會(huì)自動(dòng)刪除。
如果方法參數(shù)有多個(gè),且參數(shù)類型差別不大,IntelliJ idea alt+Enter提供的修改可能是錯(cuò)誤的,譬如你刪除了第5個(gè)參數(shù),Idea可能會(huì)把第4個(gè)參數(shù)刪除了,然后更改實(shí)際函數(shù)中的參數(shù)名,造成參數(shù)錯(cuò)位,就會(huì)編譯報(bào)錯(cuò),這種情況建議使用Ctrl+F6的GUi界面來(lái)操作。
把一個(gè)方法通過(guò)F6移動(dòng)到另一個(gè)Class時(shí),Move操作成功后,移過(guò)去的方法如果使用了原來(lái)Class中的字段,就會(huì)編譯不過(guò)。這種情況不用擔(dān)心,一般的步驟是先移動(dòng),然后解決編譯報(bào)錯(cuò)。
移動(dòng)方法時(shí),方法增加的Class一般不選擇抽象方法,這樣會(huì)把方法移動(dòng)到抽象方法中,正確的做法是,增加的類型參數(shù)是預(yù)期的抽象類的子類,這樣就可以了
?
在建工廠類或接口時(shí),可以先寫(xiě)Class Name,然后使用Idea的快捷鍵來(lái)創(chuàng)建Class,Interface,Method,Field
去除if else 的常用方法是每個(gè)分支就是一個(gè)對(duì)象,然后實(shí)現(xiàn)相同的接口;把if else分支的判斷邏輯放到Factory類,這樣代碼就清凈了。
擴(kuò)展性和可維護(hù)性都增加了,擴(kuò)展性:如果增加或減少一種場(chǎng)景,只修改工廠類或增加或刪除新類即可,與此不相關(guān)的場(chǎng)景不會(huì)影響 ,不用知道其它情景的實(shí)現(xiàn),也不用重新測(cè)試這些沒(méi)有涉及的場(chǎng)景。
并且 業(yè)務(wù)邏輯和每個(gè)場(chǎng)景都可以獨(dú)立寫(xiě)測(cè)試用例。如果有重復(fù)代碼,不僅看得見(jiàn),更能去得掉。重復(fù)代碼抽取到父類中即可。也可以定義一個(gè)接口,抽象類來(lái)實(shí)現(xiàn),業(yè)務(wù)類再繼承抽象類。重復(fù)的字段或方法放在抽象類中。
Idea中的快捷鍵:
Ctrl+Alt+F12:打開(kāi)某個(gè)package;
Ctrl+F12:打開(kāi)File Structure
Ctrl+Alt+B:接口的實(shí)現(xiàn)類,抽象類的子類
Alt+F7:查找使用字段,方法
Ctrl+E:最近使用的文件,在F6移動(dòng)操作時(shí)很有用
Ctrl+Alt+LeftArrow鍵:上一個(gè)操作代碼位置。很遺憾,遠(yuǎn)程桌面中無(wú)法使用,只能使用鼠標(biāo)點(diǎn)擊工具欄上的按鈕
Ctrl+Shift:移動(dòng)方法或字段或語(yǔ)句
在equals方法的左或右邊的對(duì)象上按Alt+Enter,會(huì)出現(xiàn)Flip,來(lái)互換
Ctrl+B轉(zhuǎn)到定義處,再按Ctrl+B,返回
Alt+insert:構(gòu)造函數(shù),get,set,overrider
Ctrl+Alt+T:surround with try catch
在方法或類上按Ctrl+shift+T,用來(lái)創(chuàng)建測(cè)試用例
Ctrl+P:查看方法參數(shù)
Ctrl+Q:查看API
Shift+F6:重命名
Ctrl+Alt+n:內(nèi)聯(lián),即獨(dú)立的方法整合到調(diào)用中,被內(nèi)聯(lián)的方法就去掉了
在進(jìn)行重構(gòu)操作的Class代碼中按Ctrl+Z,即可undo剛才的操作
compare with clipboard:先復(fù)制一段文本,然后在idea中選中一段文字,在選中文字上右鍵,選“Compare with clipboard”即可比較,identical:相同的,一致的
Ctrl+Shift+F9:compile,要做中Module或Project,光標(biāo)在一個(gè)Class文件中,就會(huì)只編譯這個(gè)文件,如果引用其它非APIclass,則編譯不過(guò)
Idea中有在跑測(cè)試用例,編譯Module或Project時(shí),才會(huì)發(fā)現(xiàn)哪些Class中沒(méi)有編譯過(guò)。提交代碼前一定要先編譯下或先跑下測(cè)試用例
git:
git fetch//獲取origin上的更新
git merge//和本地代碼合并,如果有clifict,還要resolve才能提交
git add <some files>//暫存數(shù)據(jù)(標(biāo)識(shí)要commit的本地所有文件),.代表所有本地文件(除了ignore文件中標(biāo)識(shí)的)。也可以add指定文件名的單個(gè)文件
git status -s//查看本地倉(cāng)庫(kù)的修改狀態(tài),如果沒(méi)有輸出,說(shuō)明沒(méi)有需要提交的。
git commit -m "注釋"//提交到本地倉(cāng)庫(kù)
git push origin master//提交到git服務(wù)器origin的master分支
git branch//查看
git log --oneline -5
測(cè)試用例中mock使用的回顧:
spy,如果不想執(zhí)行spy的方法,就使用doReturn,不然,被spy的方法還會(huì)被執(zhí)行
直接貼個(gè)例子吧,
doReturn(true).when(spy).getDataByDataType(eq(spySubnet), anyString(), anyString()); spy.sync(spySubnet);verify(ImManageImp).doData();verify(ImManageImp).clearWork();//等價(jià)于verify(ImManageImp,times(1)).clearWork() //Mockito的assertThat方法,可以把不匹配的expect和actual數(shù)據(jù)都打印出來(lái),預(yù)期的數(shù)據(jù)需要使用is(),is()的功能也很強(qiáng)大
assertThat(localTempFle.exists(), is(false)); } catch (Exception e) {throw new IllegalArgumentException("UT Fail", e);}}@Testpublic void should_doDataClearWork_deleteTempPath_when_Type_not_equals_gv3() {try {Subnet spySubnet = spy(getNotGv3Subnet());StmFileExporter StmFileExporter = new StmFileExporter(targetPath, fileStyle);StmFileExporter spy = spy(StmFileExporter);spy.sync(spySubnet);verify(spy, times(0)).doStmSync(spySubnet);} catch (Exception e) {throw new IllegalArgumentException("UT Fail", e);}}}
累并充實(shí)著吧。
就想起這么多了
再總結(jié)一下,上面去除if else的重構(gòu)過(guò)程,是LSP的一個(gè)體現(xiàn),即父類出來(lái)的地方,都可以用子類替代
測(cè)試用例的書(shū)寫(xiě)原則,對(duì)象完成一個(gè)行為后,肯定要改變什么,通過(guò)IO操作改變了外設(shè)上的數(shù)據(jù)、改變了對(duì)象的狀態(tài),測(cè)試用例只需要覆蓋變化即可。
被測(cè)對(duì)象中的行為在執(zhí)行時(shí),使用了其它對(duì)象A,對(duì)象A中有些API的使用,導(dǎo)致無(wú)法正常寫(xiě)測(cè)試用例,這種場(chǎng)景,需要將對(duì)象A注入到被測(cè)對(duì)象,即給被測(cè)對(duì)象增加一個(gè)協(xié)作者,因?yàn)?span style="color:#0000ff;">被測(cè)對(duì)象的行為不能單獨(dú)完成。
多用組合,少用繼承。組合時(shí),注入需要協(xié)作的對(duì)象,即可方便寫(xiě)測(cè)試用例。
新增對(duì)象時(shí),一般會(huì)采用set方法而不在constructor中新增一個(gè)入?yún)?#xff0c;這樣改動(dòng)最小,對(duì)已有對(duì)象影響最小。
LSP:
1.概述: 派生類(子類)對(duì)象能夠替換其基類(父類)對(duì)象被調(diào)用
2.概念:
里氏代換原則(Liskov Substitution Principle LSP)面向?qū)ο笤O(shè)計(jì)的基本原則之一。 里氏代換原則中說(shuō),任何基類可以出現(xiàn)的地方,子類一定可以出現(xiàn)。 LSP是繼承復(fù)用的基石,只有當(dāng)衍生類可以替換掉基類,軟件單位的功能不受到影響時(shí),基類才能真正被復(fù)用,而衍生類也能夠在基類的基礎(chǔ)上增加新的行為。里氏代換原則是對(duì)“開(kāi)-閉”原則的補(bǔ)充。實(shí)現(xiàn)“開(kāi)-閉”原則的關(guān)鍵步驟就是抽象化。而基類與子類的繼承關(guān)系就是抽象化的具體實(shí)現(xiàn),所以里氏代換原則是對(duì)實(shí)現(xiàn)抽象化的具體步驟的規(guī)范。(源自百度百科)
?
3.子類為什么可以替換父類的位置?:
當(dāng)滿足繼承的時(shí)候,父類肯定存在非私有成員,子類肯定是得到了父類的這些非私有成員(假設(shè),父類的的成員全部是私有的,那么子類沒(méi)辦法從父類繼承任何成員,也就不存在繼承的概念了)。既然子類繼承了父類的這些非私有成員,那么父類對(duì)象也就可以在子類對(duì)象中調(diào)用這些非私有成員。所以,子類對(duì)象可以替換父類對(duì)象的位置。
?
4.里氏代換原則優(yōu)點(diǎn):
需求變化時(shí),只須繼承,而別的東西不會(huì)改變。由于里氏代換原則才使得開(kāi)放封閉成為可能。這樣使得子類在父類無(wú)需修改的話就可以擴(kuò)展。
?
總結(jié)
以上是生活随笔為你收集整理的重构一个功能块的总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 用户访问网站的基本流程
- 下一篇: CXF+Spring+Tomcat简明示