重构是指这样一个过程:在不改变代码外在行为的前提下,对代码做出修改,以改变程序的内部结构,本质是指代码写好后的设计改进,提高可理解性,降低修改成本。
1.三次原则,多次重复的事情,想办法重构
2.添加新的功能时候
3.修补错误时重构
4.复审代码时候重构
1.完成今天的任务,我们还要考虑明天;
2.难于阅读的程序,难以修改;
3.逻辑重复的程序,难以修改;
4.添加新行为时,要修改已有代码,难以理解;
5.带复杂逻辑的程序,难以修改;
6.每次重构可以加深对代码的理解,不至于遗忘;
1.容易阅读;
2.所有逻辑只在唯一地点指定;
3.新的改动不会危及现有行为;
4.简单的表达逻辑;
计算机科学是这样一门科学:它相信所有问题都可以通过增加一个间接层来解决。----Kentn Beck
好的变量命名,可以减少注释,提高可阅读性。
一些没有调用数据库的操作,单纯操作对象提取Utill类,对象设值,提取方法到对象中。
去除一些临时变量,提取方法,临时变量助长冗长复杂函数。
1.重复的代码,相同的表达式,两个互为兄弟子类内含相同表达式;
2.过长的函数,寻找注释,一行注释,也可提炼一个函数;
3.过大的类
4.过长的参数列,对象传递,数据泥团,有关系的数据,提取新对象。
5.发散式变化,散弹式修改,(修改一个点,要修改很多处),放到一个类型,有点ddd的味道;
6.单一原则,一个方法只做一件事,返回数据简洁,不返回多余字段。
7.临时字段,过度耦合消息链;中间人,多一层调用,委托太多
8.过多的注释,有注释是好事,过多注释是代码有问题,方法名是一个很好的解释。
9.太多中间层,有较多无用的层次;
10.switch过多地方使用,添加case,统一到一个地方。大量的if else,可以尝试这样优化;https://www.cnblogs.com/jun-ma/p/4967839.html
自动化测试类,assert断言一类,比较结果,小的功能,立即添加测试。
一些优化技巧:
内联函数,内联临时变量。将该变量的引用动作,替换为对他赋值的哪个表达式自身。
变量声明改成final定义,检查是否的确只被赋值一次。
移除对参数的赋值;按值传递,按引用传递。
以查询取代临时变量;
double basePrice = 3*ww;
if(ss >10000){
}else{
}
演变:
double basePrice (){
return 3*ww;}
if(basePrice () >10000){
}else{
}
函数本体,替换成一个算法;
如java8 的map
内部类使用,移除萎缩的类;
声明常量替换魔法数,使用枚举等;
简化条件表达式,合并重复的条件片段;
移除控制标记,使用break,continue,return等,单一入口原则;
函数的名称很重要
过多的参数,无用的参数,多态
查询和修改分离;
继承,字段上移,如都有id等,baseRequest;
提炼接口,责任划分是通过多继承实现,java只提供单继承,但是接口可以实现。
# 代码整洁之道整理: ## 1.整洁代码 为什么需要整洁代码,整洁对代码的意义? 1. 要成为好的程序员 2.槽糕和混乱的代码是有代价的 3.制造混乱无助于赶上期限,做得快唯一方法是始终尽可能保存代码整洁,比如病人在手术前请求医生别洗手,那会花太多时间,医生应该拒绝遵守,如果遵守就是一种不专业的态度。 程序员遵从了不了解混乱风险的经理的意愿,也是不专业的做法。 ## 2.有意义的命名 1. 名副其实 2. 避免误导, o 0 1 l 3. 有意义的区分 4. 使用读的出来的名称 5. 使用可以搜索的名称 6. 明确是王道,避免思维映射 7. 避免使用编码 phoneString phoneNumber 8. 每个概念对应一个词,一以贯之,controllers,managers fetch,get 9. 别用双关语 add是双关语,insert,append更合适 10. 使用解决方案领域名词,JobQueue,Event 11. 添加有意义的语境 一些前缀一类的,addrFirstName 比Address更精确 ## 3. 函数 1. 短小,通常函数不该长于一屏 2. 只做一件事 3. 每个函数一个抽象层级,Result 4. 使用描述性的名词 5. 函数的参数 尽量避免3个以上 6. 使用异常代替返回的错误码 7. 不要重复 8. 结构化编程,每个函数只有一个入口,一个出口, 函数足够短小,出现return,break,continue没有坏处 9. 先想什么就写什么,然后打磨它,初稿打磨成心目中的样子 ## 4. 注释 1.注释不能美化代码,用代码来解释 2.写好注释,对意图解释,或者警示一类的,不要写混乱,多余的注释 ## 5. 格式 1.代码有一定格式,团队规则,共同认同的一种格式 ## 6. 对象和数据结构 1.自动添加赋值器和取值器,将私有变量公之于众的问题, 隐藏实现并非只是在变量之间放在一个函数层那么简单。隐藏实现关乎抽象,类并不能简单地用取值器和赋值器将其变量推向外间,而是暴露抽象接口, 以便用户无需了解数据实现就能操作数据本体。 2. 数据和对象的反对称性 二分原理:过程式代码(使用数据结构的代码)便于在不改动既有数据结构的前提下添加新函数,面向对象代码便于在不改动既有函数的前提下添加新类。 过程式代码难以添加新的数据结构,因为必须修改所有函数,面向对象代码难以添加新函数,因为必须修改所有类。 一切都是对象只是个传说,有时候想要在简单的数据结构上做一些过程式的操作。 eg:不同形状算面积,正方形方的,圆的,长方形 3.得墨忒耳律; 方法不应调用由任何函数返回的对象的方法,换言之只跟朋友谈话,不与陌生人谈话。不连串的调用(火车失事) 总结:对象暴露行为,隐藏数据,便于添加新对象类型而无需修改既有行为,同时也难以在既有对象中添加新行为。数据结构暴露数据,没有明显行为。 便于向既有数据结构添加新行为,同时也难以向既有函数添加新数据结构。 ## 7,错误处理 1. 使用异常而非返回码,调用者简洁 2. 单独的异常返回类 3. 别返回null值,也不要传递null值 ## 8. 边界 1.使用第三方代码,Map,建议不要将Map在系统中传递,把它保留在类或者近亲类中。 使用方还要强转一下类型,内部封装,直接返回。 2.Adapter模式 带着问题去测试。 ## 9. 单元测试 1.要保证测试代码的整洁性 ## 10. 类 1.类应该短小,单一权责,内聚(只有少量的实体变量) 依赖倒置原则,类应该依赖于抽象而不是依赖于具体细节 ## 11. 系统 1.将系统的构造与使用分开, 2.java代理 3.测试驱动系统架构 ## 哪些代码的坏味道: 1.重复的代码,相同的表达式,两个互为兄弟子类内含相同表达式; 2.过长的函数,寻找注释,一行注释,也可提炼一个函数; 3.过大的类 提炼函数,接口,使用继承等。 4.过长的参数列,对象传递,数据泥团,有关系的数据,提取新对象。 5.发散式变化,散弹式修改,(修改一个点,要修改很多处),放到一个类型,有点ddd的味道; 6.单一原则,一个方法只做一件事,返回数据简洁,不返回多余字段。 7.临时字段,过度耦合消息链;中间人,多一层调用,委托太多 8.过多的注释,有注释是好事,过多注释是代码有问题,方法名是一个很好的解释。 9.太多中间层,有较多无用的层次; # api系统代码重构想法整理: ## 1.api方法的命名规范 如 ParameterConvert 类里一些方法命名 ## 2.api代码逻辑下沉 ``` private void saveProjectUser(Long userId, String userRealName, Long projectId) { //TODO 封装下沉 ProjectUser projectUser = new ProjectUser(); projectUser.setUserName(userRealName); projectUser.setUserId(userId); projectUser.setProjectId(projectId); projectUser.setRoleType(RoleType.SUPER_ADMIN.getValue()); projectUser.setType(ProjectUserType.PROJECT.getType()); projectUser.setNotifySwitch(NotificationSwitchType.open.getType()); projectUserService.save(projectUser); } ``` ## 3.参数命名规范,有意义的参数名,如 ``` for (int i = 0; i < projectRequest.getUserId().length; i++) { if (projectRequest.getUserId()[i] == null || projectRequest.getUserId()[i].longValue() == AuthHolder.getOpsId().get()) { continue; } ProjectUser projectUser = new ProjectUser(); if (projectRequest.getUserRealName() != null && projectRequest.getUserRealName().length > i) { projectUser.setUserName(projectRequest.getUserRealName()[i]); } projectUser.setUserId(projectRequest.getUserId()[i]); projectUser.setProjectId(projectId); if (projectRequest.getRoleType() != null && projectRequest.getRoleType().length > i) { projectUser.setRoleType(projectRequest.getRoleType()[i]); } projectUser.setType(ProjectUserType.PROJECT.getType()); projectUserService.save(projectUser); } ``` ## 4.封装粒度不够,大段代码要拆分,公共方法要下沉,如 ``` private BaseResult getBaseResult(Page page) { ListprojectDTOList = Lists.newArrayList(); ; if (page == null || CollectionUtils.isEmpty(page.getRecords())) { PageResponse projectDTOPageResult = new PageResponse<>(projectDTOList, Constant.DEFAULT_PAGE, Constant.DEFAULT_PAGESIZE, Constant.DEFAULT_TOTAL_PAGESIZE); return new DataResult(projectDTOPageResult); } List projecList = page.getRecords(); projecList.forEach(project -> { ProjectUser projectUser = null; boolean discardPrivilige = false; if (project.getUserId() != null) { projectUser = projectUserService.getUniqueProjectUser(project.getUserId(), project.getId()); //TODO 单一的方法进行封装 if (AuthHolder.getOpsId().get().longValue() == project.getUserId() || (AuthHolder.getSuperUser().isPresent() && AuthHolder.getSuperUser().get())) { discardPrivilige = true; } else { ProjectUser projectLoginUser = projectUserService.getUniqueProjectUser(AuthHolder.getOpsId().get(), project.getId()); discardPrivilige = (projectLoginUser == null || projectLoginUser.getRoleType() == RoleType.USER.getValue()) ? false : true; } } ProjectDTO projectDTO = ProjectConvert.getDto(project, projectUser == null ? "管理员转移" : projectUser.getUserName()); projectDTO.setDiscardPrivilige(discardPrivilige); projectDTOList.add(projectDTO); }); PageResponse projectDTOPageResult = new PageResponse<>(projectDTOList, page.getCurrent(), page.getSize(), page.getTotal()); return new DataResult(projectDTOPageResult); } ``` ``` if (api.getDemandId() != null && api.getDemandId() > 0L && apiRequest.getNotifySwitch() != null && apiRequest.getNotifySwitch() > 0) { Event event = new Event(api.getId(), api.getProjectId(), api.getModuleId(), api.getDemandId(), EventState.api_info_modify, true); noticationService.sendTeambitionMsg(event); } ``` ## 5.不再使用的逻辑去除,如 ``` List opsUsers = projectManageService.getOpsUsers(name); List userDTOs = new ArrayList<>(); //TODO 不在使用的逻辑去除 if (!CollectionUtils.isEmpty(opsUsers)) { opsUsers.forEach(opsUser -> { Map opsDeptMap = null; // try { // opsDeptMap = passportFacadeServiceClient.getDeptsByUid(opsUser.getId()); // } catch (Exception e) { // // } // Map opsDeptMap = null; String[] opsDeptName = {""}; if (opsDeptMap != null) { for (Long key : opsDeptMap.keySet()) { OpsDept opsDept = opsDeptMap.get(key); opsDeptName[0] = opsDept == null ? "" : opsDept.getName(); break; } } UserDTO userDTO = ObjectToVOUtils.UserToVO(opsUser, opsDeptName[0]); userDTOs.add(userDTO); }); } ``` ## 6. 单一职责,一个方法只做一件事 ``` private SearchAllDTO getSearchAllDTO(Boolean justName, Api api) { SearchAllDTO searchAllDTO = new SearchAllDTO(); if (justName) { searchAllDTO.setType(SearchType.API_NAME.name()); searchAllDTO.setZhType(SearchType.API_NAME.getDescription()); searchAllDTO.setShowKeyWords(api.getName()); } else { searchAllDTO.setType(SearchType.API_URL.name()); searchAllDTO.setZhType(SearchType.API_URL.getDescription()); //加上Contentpath, Project project = projectService.selectById(api.getProjectId()); if(project == null){ return null; }else if (project != null && StringUtils.isNotEmpty(project.getContentPath())) { searchAllDTO.setShowKeyWords(project.getContentPath() + api.getUrl()); } else { searchAllDTO.setShowKeyWords(api.getUrl()); } } searchAllDTO.setApiId(api.getId()); searchAllDTO.setModuleId(api.getModuleId()); searchAllDTO.setProjectId(api.getProjectId()); searchAllDTO.setName(api.getName()); searchAllDTO.setUrl(api.getUrl()); return searchAllDTO; } ```