• 设计模式简记-快速改善代码质量的编程规范


    4.2 快速改善代码质量的编程规范

    4.2.1 命名

    命名的一个原则就是以能准确达意为目标

    4.2.1.1 多长合适
    • 作用域大的用更达意的长命名,如类名;反之用短命名
    4.2.1.2 利用上下文

    如下代码:不应在成员变量的命名中重复添加“user”这样一个前缀单词,而应直接命名为 name、password、avatarUrl

    public class User {
      private String userName;
      private String userPassword;
      private String userAvatarUrl;
      //...
    }
    
    4.2.1.3 命名要可读、可搜索
    • 可读,指的是不要用一些特别生僻、难发音的英文单词来命名。如:plateaux, eyrie

    • 可搜索:经常会用“关键词联想”的方法来自动补全和搜索。比如,键入某个对象“.get”,希望 IDE 返回这个对象的所有 get 开头的方法。

      统一规约很重要,都用“selectXXX”表示查询,就不要用“queryXXX”;都用“insertXXX”表示插入一条数据,要不用“addXXX”

    4.2.1.4 如何命名接口和抽象类
    • 接口命名:两种比较常见的方式:
      1. 加前缀“I”,表示一个 Interface。比如 IUserService;
      2. 不加前缀,实现类加Impl。如UserService,实现类UserServiceImpl
    • 抽象类命名:加前缀“Abstract”,如AbstractUserService

    4.2.2 注释

    4.2.2.1 该写什么?
    • 做什么、为什么、怎么做
    /**
    * (what) Bean factory to create beans. 
    * 
    * (why) The class likes Spring IOC framework, but is more lightweight. 
    *
    * (how) Create objects from different sources sequentially:
    * user specified object > SPI > configuration > default object.
    */
    public class BeansFactory {
      // ...
    }
    
    4.2.2.2 注释要多吗?
    • 类和函数一定要写注释,而且要写得尽可能全面、详细;
    • 函数内部的注释要相对少一些,一般都是靠好的命名、提炼函数、解释性变量、总结性注释来提高代码的可读性。

    4.2.3 代码风格

    • [x] 类和函数不要超过一个显示屏的垂直高度;
    • [x] 一行代码最长不能超过 IDE 显示的宽度;
    • [x] 善用空行分割单元块
    • [x] 两格缩进节省空间,不要用TAB(tab与空格混用的情况下在不同IDE会显示不一致)
    • [x] 大括号是否要另起一行?不用
    • [x] 类中成员的排列顺序:
      1. 成员变量排在函数的前面;
      2. 成员变量之间或函数之间,按照“先静态、后普通”的方式来排列;
      3. 成员变量之间或函数之间,还会按照作用域范围从大到小的顺序来排列,先 public ,再 protected ,最后 private 。

    4.2.4 实用编程技巧

    4.2.4.1 代码分隔成更小的代码块
    • 阅读代码的习惯都是,先看整体再看细节。所以,要有模块化和抽象思维,善于将大块的复杂逻辑提炼成类或者函数,屏蔽掉细节,让阅读代码的人不至于迷失在细节中,这样能极大地提高代码的可读性。

      // 重构前的代码
      public void invest(long userId, long financialProductId) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, (calendar.get(Calendar.DATE) + 1));
        if (calendar.get(Calendar.DAY_OF_MONTH) == 1) {
          return;
        }
        //...
      }
      
      // 重构后的代码:提炼函数之后逻辑更加清晰
      public void invest(long userId, long financialProductId) {
        if (isLastDayOfMonth(new Date())) {
          return;
        }
        //...
      }
      
      public boolean isLastDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, (calendar.get(Calendar.DATE) + 1));
        if (calendar.get(Calendar.DAY_OF_MONTH) == 1) {
         return true;
        }
        return false;
      }
      
    4.2.4.2 避免函数参数过多
    • 考虑函数是否职责单一,是否能通过拆分成多个函数的方式来减少参数

      public User getUser(String username, String telephone, String email);
      
      // 拆分成多个函数
      public User getUserByUsername(String username);
      public User getUserByTelephone(String telephone);
      public User getUserByEmail(String email);
      
    • 将函数的参数封装成对象

      public void postBlog(String title, String summary, String keywords, String content, String category, long authorId);
      
      // 将参数封装成对象
      public class Blog {
        private String title;
        private String summary;
        private String keywords;
        private Strint content;
        private String category;
        private long authorId;
      }
      public void postBlog(Blog blog);
      
    4.2.4.3 勿用函数参数来控制逻辑
    • true 的时候走这块逻辑,false 的时候走另一块逻辑。违背了单一职责原则和接口隔离原则。将其拆成两个函数,可读性上也要更好

      public void buyCourse(long userId, long courseId, boolean isVip);
      
      // 将其拆分成两个函数
      public void buyCourse(long userId, long courseId);
      public void buyCourseForVip(long userId, long courseId);
      
    4.2.4.4 函数设计要职责单一
    public boolean checkUserIfExisting(String telephone, String username, String email)  { 
      if (!StringUtils.isBlank(telephone)) {
        User user = userRepo.selectUserByTelephone(telephone);
        return user != null;
      }
      
      if (!StringUtils.isBlank(username)) {
        User user = userRepo.selectUserByUsername(username);
        return user != null;
      }
      
      if (!StringUtils.isBlank(email)) {
        User user = userRepo.selectUserByEmail(email);
        return user != null;
      }
      
      return false;
    }
    
    // 拆分成三个函数
    public boolean checkUserIfExistingByTelephone(String telephone);
    public boolean checkUserIfExistingByUsername(String username);
    public boolean checkUserIfExistingByEmail(String email);
    
    4.2.4.5 移除过深的嵌套层次
    • 去掉多余的 if 或 else 语句

      // 示例一
      public double caculateTotalAmount(List<Order> orders) {
        if (orders == null || orders.isEmpty()) {
          return 0.0;
        } else { // 此处的else可以去掉
          double amount = 0.0;
          for (Order order : orders) {
            if (order != null) {
              amount += (order.getCount() * order.getPrice());
            }
          }
          return amount;
        }
      }
      
      // 示例二
      public List<String> matchStrings(List<String> strList,String substr) {
        List<String> matchedStrings = new ArrayList<>();
        if (strList != null && substr != null) {
          for (String str : strList) {
            if (str != null) { // 跟下面的if语句可以合并在一起
              if (str.contains(substr)) {
                matchedStrings.add(str);
              }
            }
          }
        }
        return matchedStrings;
      }
      
    • 使用编程语言提供的 continue、break、return 关键字,提前退出嵌套

      // 重构前的代码
      public List<String> matchStrings(List<String> strList,String substr) {
        List<String> matchedStrings = new ArrayList<>();
        if (strList != null && substr != null){ 
          for (String str : strList) {
            if (str != null && str.contains(substr)) {
              matchedStrings.add(str);
              // 此处还有10行代码...
            }
          }
        }
        return matchedStrings;
      }
      
      // 重构后的代码:使用continue提前退出
      public List<String> matchStrings(List<String> strList,String substr) {
        List<String> matchedStrings = new ArrayList<>();
        if (strList != null && substr != null){ 
          for (String str : strList) {
            if (str == null || !str.contains(substr)) {
              continue; 
            }
            matchedStrings.add(str);
            // 此处还有10行代码...
          }
        }
        return matchedStrings;
      }
      
    • 调整执行顺序来减少嵌套

      // 重构前的代码
      public List<String> matchStrings(List<String> strList,String substr) {
        List<String> matchedStrings = new ArrayList<>();
        if (strList != null && substr != null) {
          for (String str : strList) {
            if (str != null) {
              if (str.contains(substr)) {
                matchedStrings.add(str);
              }
            }
          }
        }
        return matchedStrings;
      }
      
      // 重构后的代码:先执行判空逻辑,再执行正常逻辑
      public List<String> matchStrings(List<String> strList,String substr) {
        if (strList == null || substr == null) { //先判空
          return Collections.emptyList();
        }
      
        List<String> matchedStrings = new ArrayList<>();
        for (String str : strList) {
          if (str != null) {
            if (str.contains(substr)) {
              matchedStrings.add(str);
            }
          }
        }
        return matchedStrings;
      }
      
    • 将部分嵌套逻辑封装成函数调用,以此来减少嵌套

      // 重构前的代码
      public List<String> appendSalts(List<String> passwords) {
        if (passwords == null || passwords.isEmpty()) {
          return Collections.emptyList();
        }
        
        List<String> passwordsWithSalt = new ArrayList<>();
        for (String password : passwords) {
          if (password == null) {
            continue;
          }
          if (password.length() < 8) {
            // ...
          } else {
            // ...
          }
        }
        return passwordsWithSalt;
      }
      
      // 重构后的代码:将部分逻辑抽成函数
      public List<String> appendSalts(List<String> passwords) {
        if (passwords == null || passwords.isEmpty()) {
          return Collections.emptyList();
        }
      
        List<String> passwordsWithSalt = new ArrayList<>();
        for (String password : passwords) {
          if (password == null) {
            continue;
          }
          passwordsWithSalt.add(appendSalt(password));
        }
        return passwordsWithSalt;
      }
      
      private String appendSalt(String password) {
        String passwordWithSalt = password;
        if (password.length() < 8) {
          // ...
        } else {
          // ...
        }
        return passwordWithSalt;
      }
      
    4.2.4.6 使用解释性变量
    • 常量取代魔法数字

      public double CalculateCircularArea(double radius) {
        return (3.1415) * radius * radius;
      }
      
      // 常量替代魔法数字
      public static final Double PI = 3.1415;
      public double CalculateCircularArea(double radius) {
        return PI * radius * radius;
      }
      
    • 使用解释性变量来解释复杂表达式

      if (date.after(SUMMER_START) && date.before(SUMMER_END)) {
        // ...
      } else {
        // ...
      }
      
      // 引入解释性变量后逻辑更加清晰
      boolean isSummer = date.after(SUMMER_START)&&date.before(SUMMER_END);
      if (isSummer) {
        // ...
      } else {
        // ...
      } 
      
    4.2.4.7 善用编程语言提供的语法糖,如lambda表达式

    https://www.cnblogs.com/franson-2016/p/5593080.html

    list循环操作

    String[] atp = {"Rafael Nadal", "Novak Djokovic",  
           "Stanislas Wawrinka",  
           "David Ferrer","Roger Federer",  
           "Andy Murray","Tomas Berdych",  
           "Juan Martin Del Potro"};  
    List<String> players =  Arrays.asList(atp);  
      
    // 以前的循环方式  
    for (String player : players) {  
         System.out.print(player + "; ");  
    }  
      
    // 使用 lambda 表达式以及函数操作(functional operation)  
    players.forEach((player) -> System.out.print(player + "; "));  
       
    // 在 Java 8 中使用双冒号操作符(double colon operator)  
    players.forEach(System.out::println);
    

    实现Runnable接口

    // 1.1使用匿名内部类  
    new Thread(new Runnable() {  
        @Override  
        public void run() {  
            System.out.println("Hello world !");  
        }  
    }).start();  
      
    // 1.2使用 lambda expression  
    new Thread(() -> System.out.println("Hello world !")).start();  
      
    // 2.1使用匿名内部类  
    Runnable race1 = new Runnable() {  
        @Override  
        public void run() {  
            System.out.println("Hello world !");  
        }  
    };  
      
    // 2.2使用 lambda expression  
    Runnable race2 = () -> System.out.println("Hello world !");  
       
    // 直接调用 run 方法(没开新线程哦!)  
    race1.run();  
    race2.run();
    

    使用Lambdas排序集合

    // 1.1 使用匿名内部类根据 name 排序 players  
    Arrays.sort(players, new Comparator<String>() {  
        @Override  
        public int compare(String s1, String s2) {  
            return (s1.compareTo(s2));  
        }  
    });
    // 1.2 使用 lambda expression 排序 players  
    Comparator<String> sortByName = (String s1, String s2) -> (s1.compareTo(s2));  
    Arrays.sort(players, sortByName);  
      
    // 1.3 也可以采用如下形式:  
    Arrays.sort(players, (String s1, String s2) -> (s1.compareTo(s2)));  
    
  • 相关阅读:
    计算最大公因数
    最大子序列和问题
    C++三大函数:析构函数、复制构造函数和operator=
    C++函数返回值传递
    C++动态内存分配
    Halcon Assistants
    网格细分算法
    HDevelop Guide
    MeshLab
    point cloud registration
  • 原文地址:https://www.cnblogs.com/wod-Y/p/13055933.html
Copyright © 2020-2023  润新知