日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

重构一个功能块的总结

發(fā)布時間:2025/3/20 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 重构一个功能块的总结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

因為Leader不建議占用上班時間搞這個,基本上都是加班搞的

在做這個事的過程中,對IntelliJ idea更加熟悉,回顧下Mocikitto中spy,mock,verify,when的使用,這次重構(gòu)基本上是小步快走,層層分離

IntelliiJ idea:
重構(gòu)手法:如果想把一個方法移動到另一個class中,可以通過method增加一個Class類型的參數(shù),然后將光標(biāo)放在方法名的任何字符上【若選中方法名,則F6會失效】,按F6,在彈出的對話框中選擇預(yù)期的Class【因為這個方法的參數(shù)是其它類型的對象】

更改方法的參數(shù)個數(shù)時,可以會調(diào)用處更改,從上往下進行,或按Ctrl+F6在調(diào)用的GUI界面操作。IntelliJ Idea的自動操作往往留一些尾巴,譬如,刪除一個構(gòu)造函數(shù)的一個參數(shù),參數(shù)賦值的字段和構(gòu)造中賦值語句不會自動刪除。

如果方法參數(shù)有多個,且參數(shù)類型差別不大,IntelliJ idea alt+Enter提供的修改可能是錯誤的,譬如你刪除了第5個參數(shù),Idea可能會把第4個參數(shù)刪除了,然后更改實際函數(shù)中的參數(shù)名,造成參數(shù)錯位,就會編譯報錯,這種情況建議使用Ctrl+F6的GUi界面來操作。

把一個方法通過F6移動到另一個Class時,Move操作成功后,移過去的方法如果使用了原來Class中的字段,就會編譯不過。這種情況不用擔(dān)心,一般的步驟是先移動,然后解決編譯報錯。

移動方法時,方法增加的Class一般不選擇抽象方法,這樣會把方法移動到抽象方法中,正確的做法是,增加的類型參數(shù)是預(yù)期的抽象類的子類,這樣就可以了

?

在建工廠類或接口時,可以先寫Class Name,然后使用Idea的快捷鍵來創(chuàng)建Class,Interface,Method,Field

去除if else 的常用方法是每個分支就是一個對象,然后實現(xiàn)相同的接口;把if else分支的判斷邏輯放到Factory類,這樣代碼就清凈了。
擴展性和可維護性都增加了,擴展性:如果增加或減少一種場景,只修改工廠類或增加或刪除新類即可,與此不相關(guān)的場景不會影響 ,不用知道其它情景的實現(xiàn),也不用重新測試這些沒有涉及的場景。
并且 業(yè)務(wù)邏輯和每個場景都可以獨立寫測試用例。如果有重復(fù)代碼,不僅看得見,更能去得掉。重復(fù)代碼抽取到父類中即可。也可以定義一個接口,抽象類來實現(xiàn),業(yè)務(wù)類再繼承抽象類。重復(fù)的字段或方法放在抽象類中。

Idea中的快捷鍵:
Ctrl+Alt+F12:打開某個package;
Ctrl+F12:打開File Structure
Ctrl+Alt+B:接口的實現(xiàn)類,抽象類的子類
Alt+F7:查找使用字段,方法
Ctrl+E:最近使用的文件,在F6移動操作時很有用
Ctrl+Alt+LeftArrow鍵:上一個操作代碼位置。很遺憾,遠程桌面中無法使用,只能使用鼠標(biāo)點擊工具欄上的按鈕
Ctrl+Shift:移動方法或字段或語句
在equals方法的左或右邊的對象上按Alt+Enter,會出現(xiàn)Flip,來互換
Ctrl+B轉(zhuǎn)到定義處,再按Ctrl+B,返回
Alt+insert:構(gòu)造函數(shù),get,set,overrider
Ctrl+Alt+T:surround with try catch
在方法或類上按Ctrl+shift+T,用來創(chuàng)建測試用例
Ctrl+P:查看方法參數(shù)
Ctrl+Q:查看API
Shift+F6:重命名
Ctrl+Alt+n:內(nèi)聯(lián),即獨立的方法整合到調(diào)用中,被內(nèi)聯(lián)的方法就去掉了
在進行重構(gòu)操作的Class代碼中按Ctrl+Z,即可undo剛才的操作
compare with clipboard:先復(fù)制一段文本,然后在idea中選中一段文字,在選中文字上右鍵,選“Compare with clipboard”即可比較,identical:相同的,一致的
Ctrl+Shift+F9:compile,要做中Module或Project,光標(biāo)在一個Class文件中,就會只編譯這個文件,如果引用其它非APIclass,則編譯不過
Idea中有在跑測試用例,編譯Module或Project時,才會發(fā)現(xiàn)哪些Class中沒有編譯過。提交代碼前一定要先編譯下或先跑下測試用例

git:
git fetch//獲取origin上的更新
git merge//和本地代碼合并,如果有clifict,還要resolve才能提交
git add <some files>//暫存數(shù)據(jù)(標(biāo)識要commit的本地所有文件),.代表所有本地文件(除了ignore文件中標(biāo)識的)。也可以add指定文件名的單個文件
git status -s//查看本地倉庫的修改狀態(tài),如果沒有輸出,說明沒有需要提交的。
git commit -m "注釋"//提交到本地倉庫
git push origin master//提交到git服務(wù)器origin的master分支
git branch//查看
git log --oneline -5

測試用例中mock使用的回顧:
spy,如果不想執(zhí)行spy的方法,就使用doReturn,不然,被spy的方法還會被執(zhí)行
直接貼個例子吧,

import com.download.util.Subnet; import com.file.utils.StmImManageImp; import com.file.utils.FileInfoUtil; import com.api.util.DebugPrn; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner;import java.io.File; import java.io.IOException;import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.*;@RunWith(MockitoJUnitRunner.class)//這個必須有,不然@Mock就失效了 public class StmFileExporterTest extends AbstractFileExportTest {//UT也需要去除重復(fù)private static final DebugPrn LOGGER = new DebugPrn(StmFileExporterTest.class.getName());private String targetPath;@Mock//使用Mock注解,代碼更清晰private FileInfoUtil fileStyle;@Mockprivate StmImManageImp ImManageImp;@Before//準(zhǔn)備工作public void init() throws IOException {targetPath = StmFileExporterTest.class.getResource("/com/file/fileexporter/").getPath();if (!new File(targetPath).mkdirs()) {LOGGER.info(String.format("path(%s) mkdirs failed!", targetPath));}}@Testpublic void should_doDataClearWork_deleteTempPath_when_getByDataType_is_true_and_saveFile_not_exists() {//方法名體現(xiàn)場景try {when(fileStyle.getTaskName()).thenReturn("task1");//mock掉方法的返回值String localTempPah = targetPath + fileStyle.getTaskName() + File.separator + "" + File.separator;Subnet spySubnet = spy(getGv3Subnet());//spy一個對象,因為這個對象中的File localTempFle = new File(localTempPah);if (!localTempFle.mkdirs()) {LOGGER.info(String.format("path(%s) mkdirs failed!", localTempFle));}StmFileExporter StmFileExporter = new StmFileExporter(targetPath, fileStyle);StmFileExporter spy = spy(StmFileExporter);spy.setImManageImp(ImManageImp); //Mock方法中要匹配某個參數(shù),需使用eq();doReturn,不執(zhí)行mock的相關(guān)方法
doReturn(true).when(spy).getDataByDataType(eq(spySubnet), anyString(), anyString()); spy.sync(spySubnet);verify(ImManageImp).doData();verify(ImManageImp).clearWork();//等價于verify(ImManageImp,times(1)).clearWork() //Mockito的assertThat方法,可以把不匹配的expect和actual數(shù)據(jù)都打印出來,預(yù)期的數(shù)據(jù)需要使用is(),is()的功能也很強大
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);}}}

累并充實著吧。
就想起這么多了  

再總結(jié)一下,上面去除if else的重構(gòu)過程,是LSP的一個體現(xiàn),即父類出來的地方,都可以用子類替代
測試用例的書寫原則,對象完成一個行為后,肯定要改變什么,通過IO操作改變了外設(shè)上的數(shù)據(jù)、改變了對象的狀態(tài),測試用例只需要覆蓋變化即可。
被測對象中的行為在執(zhí)行時,使用了其它對象A,對象A中有些API的使用,導(dǎo)致無法正常寫測試用例,這種場景,需要將對象A注入到被測對象,即給被測對象增加一個協(xié)作者,因為被測對象的行為不能單獨完成
多用組合,少用繼承。組合時,注入需要協(xié)作的對象,即可方便寫測試用例。
新增對象時,一般會采用set方法而不在constructor中新增一個入?yún)?#xff0c;這樣改動最小,對已有對象影響最小。


LSP:
1.概述: 派生類(子類)對象能夠替換其基類(父類)對象被調(diào)用
2.概念:
里氏代換原則(Liskov Substitution Principle LSP)面向?qū)ο笤O(shè)計的基本原則之一。 里氏代換原則中說,任何基類可以出現(xiàn)的地方,子類一定可以出現(xiàn)。 LSP是繼承復(fù)用的基石,只有當(dāng)衍生類可以替換掉基類,軟件單位的功能不受到影響時,基類才能真正被復(fù)用,而衍生類也能夠在基類的基礎(chǔ)上增加新的行為。里氏代換原則是對“開-閉”原則的補充。實現(xiàn)“開-閉”原則的關(guān)鍵步驟就是抽象化。而基類與子類的繼承關(guān)系就是抽象化的具體實現(xiàn),所以里氏代換原則是對實現(xiàn)抽象化的具體步驟的規(guī)范。(源自百度百科)
?
3.子類為什么可以替換父類的位置?:
當(dāng)滿足繼承的時候,父類肯定存在非私有成員,子類肯定是得到了父類的這些非私有成員(假設(shè),父類的的成員全部是私有的,那么子類沒辦法從父類繼承任何成員,也就不存在繼承的概念了)。既然子類繼承了父類的這些非私有成員,那么父類對象也就可以在子類對象中調(diào)用這些非私有成員。所以,子類對象可以替換父類對象的位置。
?
4.里氏代換原則優(yōu)點:
需求變化時,只須繼承,而別的東西不會改變。由于里氏代換原則才使得開放封閉成為可能。這樣使得子類在父類無需修改的話就可以擴展





?

總結(jié)

以上是生活随笔為你收集整理的重构一个功能块的总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。