代码重构的技巧方法与代码整洁之道整理

代码重构的技巧方法

重构是指这样一个过程:在不改变代码外在行为的前提下,对代码做出修改,以改变程序的内部结构,本质是指代码写好后的设计改进,提高可理解性,降低修改成本。

什么时候重构:

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) {
        List<ProjectDTO> projectDTOList = Lists.newArrayList();
        ;
        if (page == null || CollectionUtils.isEmpty(page.getRecords())) {
            PageResponse<ProjectDTO> projectDTOPageResult = new PageResponse<>(projectDTOList, Constant.DEFAULT_PAGE,
                    Constant.DEFAULT_PAGESIZE, Constant.DEFAULT_TOTAL_PAGESIZE);
            return new DataResult(projectDTOPageResult);
        }
        List<Project> 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<ProjectDTO> 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<OpsUser> opsUsers = projectManageService.getOpsUsers(name);
        List<UserDTO> userDTOs = new ArrayList<>();
        //TODO 不在使用的逻辑去除
        if (!CollectionUtils.isEmpty(opsUsers)) {
            opsUsers.forEach(opsUser -> {

                Map<Long, OpsDept> opsDeptMap = null;
//                try {
//                    opsDeptMap = passportFacadeServiceClient.getDeptsByUid(opsUser.getId());
//                } catch (Exception e) {
//
//                }
//                Map<Long, OpsDept> 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;
     }
 ```

  

 


发布了136 篇原创文章 · 获赞 65 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/jakeswang/article/details/84347732