重构一个功能块的总结

因为Leader不建议占用上班时间搞这个,基本上都是加班搞的

在做这个事的过程中,对IntelliJ idea更加熟悉,回顾下Mocikitto中spy,mock,verify,when的使用,这次重构基本上是小步快走,层层分离

IntelliiJ idea:
重构手法:如果想把一个方法移动到另一个class中,可以通过method增加一个Class类型的参数,然后将光标放在方法名的任何字符上【若选中方法名,则F6会失效】,按F6,在弹出的对话框中选择预期的Class【因为这个方法的参数是其它类型的对象】

更改方法的参数个数时,可以会调用处更改,从上往下进行,或按Ctrl+F6在调用的GUI界面操作。IntelliJ Idea的自动操作往往留一些尾巴,譬如,删除一个构造函数的一个参数,参数赋值的字段和构造中赋值语句不会自动删除。

如果方法参数有多个,且参数类型差别不大,IntelliJ idea alt+Enter提供的修改可能是错误的,譬如你删除了第5个参数,Idea可能会把第4个参数删除了,然后更改实际函数中的参数名,造成参数错位,就会编译报错,这种情况建议使用Ctrl+F6的GUi界面来操作。

把一个方法通过F6移动到另一个Class时,Move操作成功后,移过去的方法如果使用了原来Class中的字段,就会编译不过。这种情况不用担心,一般的步骤是先移动,然后解决编译报错。

移动方法时,方法增加的Class一般不选择抽象方法,这样会把方法移动到抽象方法中,正确的做法是,增加的类型参数是预期的抽象类的子类,这样就可以了

在建工厂类或接口时,可以先写Class Name,然后使用Idea的快捷键来创建Class,Interface,Method,Field

去除if else 的常用方法是每个分支就是一个对象,然后实现相同的接口;把if else分支的判断逻辑放到Factory类,这样代码就清净了。
扩展性和可维护性都增加了,扩展性:如果增加或减少一种场景,只修改工厂类或增加或删除新类即可,与此不相关的场景不会影响 ,不用知道其它情景的实现,也不用重新测试这些没有涉及的场景。
并且 业务逻辑和每个场景都可以独立写测试用例。如果有重复代码,不仅看得见,更能去得掉。重复代码抽取到父类中即可。也可以定义一个接口,抽象类来实现,业务类再继承抽象类。重复的字段或方法放在抽象类中。

Idea中的快捷键:
Ctrl+Alt+F12:打开某个package;
Ctrl+F12:打开File Structure
Ctrl+Alt+B:接口的实现类,抽象类的子类
Alt+F7:查找使用字段,方法
Ctrl+E:最近使用的文件,在F6移动操作时很有用
Ctrl+Alt+LeftArrow键:上一个操作代码位置。很遗憾,远程桌面中无法使用,只能使用鼠标点击工具栏上的按钮
Ctrl+Shift:移动方法或字段或语句
在equals方法的左或右边的对象上按Alt+Enter,会出现Flip,来互换
Ctrl+B转到定义处,再按Ctrl+B,返回
Alt+insert:构造函数,get,set,overrider
Ctrl+Alt+T:surround with try catch
在方法或类上按Ctrl+shift+T,用来创建测试用例
Ctrl+P:查看方法参数
Ctrl+Q:查看API
Shift+F6:重命名
Ctrl+Alt+n:内联,即独立的方法整合到调用中,被内联的方法就去掉了
在进行重构操作的Class代码中按Ctrl+Z,即可undo刚才的操作
compare with clipboard:先复制一段文本,然后在idea中选中一段文字,在选中文字上右键,选“Compare with clipboard”即可比较,identical:相同的,一致的
Ctrl+Shift+F9:compile,要做中Module或Project,光标在一个Class文件中,就会只编译这个文件,如果引用其它非APIclass,则编译不过
Idea中有在跑测试用例,编译Module或Project时,才会发现哪些Class中没有编译过。提交代码前一定要先编译下或先跑下测试用例

git:
git fetch//获取origin上的更新
git merge//和本地代码合并,如果有clifict,还要resolve才能提交
git add .//添加本地所有文件
git status -s//查看本地文件状态,如果没有输出,说明都处理过了。
git commit -m "注释"//提交到本地仓库
git push origin master//提交到git服务器的master分支
git branch//查看
git log --oneline -5

测试用例中mock使用的回顾:
spy,如果不想执行spy的方法,就使用doReturn,不然,被spy的方法还会被执行
直接贴个例子吧,

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也需要去除重复

    private static final DebugPrn LOGGER = new DebugPrn(StmFileExporterTest.class.getName());
    private String targetPath;
    @Mock//使用Mock注解,代码更清晰
    private FileInfoUtil fileStyle;
    @Mock
    private StmImManageImp ImManageImp;

    @Before//准备工作
    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));
        }
    }

    @Test
    public void should_doDataClearWork_deleteTempPath_when_getByDataType_is_true_and_saveFile_not_exists() {//方法名体现场景
        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方法中要匹配某个参数,需使用eq();doReturn,不执行mock的相关方法            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数据都打印出来,预期的数据需要使用is(),is()的功能也很强大           assertThat(localTempFle.exists(), is(false));
        } catch (Exception e) {
            throw new IllegalArgumentException("UT Fail", e);
        }
    }

    @Test
    public 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);
        }
    }

}

累并充实着吧。
就想起这么多了  

时间: 2024-10-11 05:07:11

重构一个功能块的总结的相关文章

如何重构一个系统

如何重构一个系统 发现一个很有意思的情况,做系统写代码多年了,遇到的需求基本上是在已有的系统上实现,从头来实现的系统基本上没有. 1 why 无论是从头是实现一个系统,还是维护一个系统,当时实现的技术可能是最先进的.规划的产品逻辑是合理的,随着时间的发展.开发人员的变更.系统的代码质量会逐渐腐化,加个Feature太麻烦,改个Bug涉及模块太多-没有单测不敢随便解,业务方抱怨技术团队响应太慢.是时候重构系统了. 对于技术团队来说,重构能力影响着系统对业务团队的响应速度.很多职位招聘的时候都要求:

学习Android开源项目-根据知乎日报API分析重构一个简单的知乎日报Android客户端

从今天开始准备开始根据之前学习的知乎日报纯净版来实现一个自己的知乎日报客户端. 每次写完的代码都会更新在Github上,每次完成一个既定目标,完成之后当天完成目标的检查并根据错误进行最优化重构. 项目地址:https://github.com/wylhyz/ZhihuDialyPrue

响应式重构,如何把一个固定页面重构为一个响应式页面:

上周末时接到公司安排下来的任务, 要我一个人在一周内把一个项目里的所有固定页面转换为响应式的页面,14个页面,虽说做成响应式不难,但是,先理解别人的代码,然后通过修改别人的代码,把一个页面转换为一个响应式的页面,还是没有那么简单的,公司觉得这个任务简单,于是把这个任务交给了我这个新手. 在重构一个页面时,我的思路如下: 一.拿到一个页面,你首先要考虑这个页面我是该重新做呢还是在现有的基础上去修改呢? 我这是这么判断的,首先看他的html结构,是否符合响应式的要求,如果符合,就在现有的基础去修改,

React组件重构:嵌套+继承 与 高阶组件

前言 在最近做的一个react项目中,遇到了一个比较典型的需要重构的场景:提取两个组件中共同的部分. 最开始通过使用嵌套组件和继承的方式完成了这次重构. 但是后来又用高阶组件重新写了一遍,发现更好一点. 在这里记录下这两种方式以便之后参考和演进. 本次重构的场景 因为场景涉及到具体的业务,所以我现在将它简化为一个简单的场景. 现在有两个黑色箱子,箱子上都有一个红色按钮,A箱子充满气体,按了按钮之后箱子里面气体变红,B箱子充满泥土,按了之后箱子里面泥土变红. 那么现在上一个简单的重构前代码: Bo

《重构:改善既有代码的设计》读书笔记

??如果一个人没有听说过<重构>这本书,那么他一定不敢说自己是程序员:如果一个人没有阅读过<重构>这本书,那么很难想象他会是一名优秀的程序员.这本书是很多公司要求Java程序员必读的三本书之一(另外两本书是<Java编程思想>和<Effective Java>),其实无关编程语言,是程序员就能够从这本书中受益. ??何谓重构?重构是对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低修改成本.重构是用微小的步伐修改程序,在这个

使用React重构百度新闻webapp前端

http://wangfupeng.coding.me/share/2016/08/06/restruct-bdnews-webapp-by-react.html 声明 本文仅仅是对前几个月使用React重构百度新闻webapp项目的一个总结和思考,不会泄露任何项目代码(文章中的代码都是fis3或其他开源产品的配置代码,fis3是百度开源产品),因此“伸手党”可绕行. 现在2016年8月,web前端技术这几年变化太快,因此一些信息的时效性非常重要,还是把时间写上比较好. 项目介绍 百度新闻的 w

代码重构之逻辑聚集

上一篇文章中写了一个重构数据结构,也就是数据聚集的例子.之前还有过一个经历,是重构一个很长的函数,过程大概就是把相关的逻辑聚集起来.我将其称为逻辑聚集.这是一个重构代码逻辑的过程. 故事是这样的.在我手上的,是一个由几百行代码组成的函数.程序整体上看起来有比较清晰的代码块,有的代码块很相似,但是细节有不同.曾经尝试修改过这个代码.但是,由于一些局部变量贯穿整个函数,在不同的地方发挥作用,而且,不同的代码块之间相互影响.所以,修改这个函数的逻辑很困难,一个小的改动就要改好几个地方.所以,就想着重构

大话重构连载16:超级大函数

事情总是这样的:当我们对一个遗留系统一忍再忍,再忍,忍,还要忍--终于积攒到某一天,实在忍无可忍了,拍案而起,不能再忍了,重构!!!事情就这样发生了.然而,在这时你突然发现,重构的工作千头万绪,真不知从何开始.堆积如山的问题此起彼伏,期望修改的设计思绪万千.这里有个想法,那里有个思路,什么都想做,却什么都做不了,真是脑子里一团乱麻.这时候,没有一个合理的步骤,清晰的计划,瞎干蛮干是十分危险的,它会为你的重构带来不可预期的未来.无数次的经验告诉我,不论是什么系统,采用什么架构,从分解大函数开始,肯

架构的坑系列:重构过程中的过度设计

架构的坑系列:重构过程中的过度设计 软件架构   2016-06-03 08:47:02 发布 您的评价:       5.0   收藏     2收藏 这个系列是 坑 系列,会说一些在系统设计,系统架构上的 坑 ,这些都是我想到哪说到哪,有像这篇一样比较宏观的 坑 ,后面的文章也会有到具体技术细节的(比如某个函数,某个系统调用) 坑 ,总之,到处都是坑,这些坑有些是我经历过的,有些是听说的,你也可以留言说说你遇到的 坑 . 这一篇,我们从 重构 这个场景来看看系统架构的设计中 过度设计 这个坑