代码整洁之道-有意义的命名

299 阅读4分钟
  1. 使用能够表明意图的命名(Use Intetion-Revealing Names)

    public class MeanifulName {
        /**
         * 下面这个方法虽然没有复杂的逻辑, 但是却让人很难看得懂.
         * 它存在如下问题:
         * 1. 方法名并没有表明这个方法的作用
         * 2. 没有表明 theList 代表什么
         * 3. theList 的元素中下标为 0 有什么特殊的含义
         * 4. 4 代表什么含义
         * 5. 返回的结果该如何使用
         */
        public static List<int[]> getThem(List<int[]> theList) {
            List<int[]> list1 = new ArrayList<>();
            for (int[] x : theList) {
                if (x[0] == 4) {
                    list1.add(x);
                }
            }
            return list1;
        }
        /**
         * 下面这段代码是上面这段代码的改进:
         * 1. 方法名表明了该方法是获取已经标记的单元格
         * 2. gameBoardCells 表明了它代表的是一个棋盘的单元格
         * 3. 使用 STATUS_VALUE 来表明下标 0 保存的是单元格的状态
         * 4. 使用 FLAGGED 来表明 4 是代表单元格被标记的状态
         * 5. flaggedCells 表明返回值是所有已被标记的单元格 
         */
        public static List<int[]> getFlaggedCells(List<int[]> gameBoardCells) {
            final int STATUS_VALUE = 0;
            final int FLAGGED = 4;
            List<int[]> flaggedCells = new ArrayList<>();
            for (int[] cell : gameBoardCells) {
                if (cell[STATUS_VALUE] == FLAGGED) {
                    flaggedCells.add(cell);
                }
            }
            return flaggedCells;
        }
        /**
         * 使用 Java 类的封装可以对以上代码进行再次改进,
         * Cell 类内部有一个表明单元格状态的属性, 客户端可以
         * 通过调用 isFlagged() 方法判断其状态
         */
        public static List<Cell> getFlaggedCells(List<Cell> gameBoardCells) {
            List<Cell> flaggedCells = new ArrayList<>();
            for (Cell cell : gameBoardCells) {
                if (cell.isFlagged()) {
                    flaggedCells.add(cell);
                }
            }
            return flaggedCellls;
        }
    
        static class Cell {
            private boolean flagged;
            public Cell() {
    
            }
            public boolean isFlagged() {
                return flagged;
            }
        }
    }
    
  2. 避免传递错误的信息(Avoid Disinformation)

    • 避免随意的缩写
    • 避免使用容易造成误解的写法: 例如小写的 l 和大写的 O
  3. 使用有意义的区别(Make Meaningful Distinctions)

    • 名称不同则意义也应该不同(If names must be different, then they should also mean something diffrent)
    /**
     * 这里 a1 和 a2 代表不同的含义
     * 所以名称也应该有所区分
     */
    public static void copyChars(char[] a1, char[] a2) {
        for (int i = 0; i < a1.length; i++) {
            a2[i] = a1[i];
        }
    }
    /**
     * 这里分别用 source 表明源字符串,
     * 用 destination 表明目标字符串
     */
    public static void copyChars(char[] source, char[] destination) {
        for (int i = 0; i < source.length; i++) {
            destination[i] = source[i];
        }
    }
    
    • 不要使用容易造成干扰的名称(Noise words are another meaningless distinction): 例如类名 ProductionInfo 和 ProductionData 其实想表达的意思是相同的, 但是不同的名称又让人觉得似乎需要对其进行区分.
  4. 使用可以读出来的名称(Use pronounceable Names):

    class DtaRcrd102 {
        private Date genymdhms;
        private Date modymdhms;
        private final String pszqint = "102";
    }
    
    class Customer {
        private Date generationTimestamp;
        private Date modificationTimestamp;
        private final String recordId = "102";
    }
    
  5. 使用可以搜索的命名(Use Searchable Names):

    例如对于一周的天数 7 这个数字来说是不好查找的, 但是将其定义为一个有意义的变量之后, DAYS_PER_WEEK = 7 就可以很方便的查找它了.

  6. 类的命名应该使用名词或者名称短语; 方法的命名应该使用动词或者动词短语

  7. 选择一个单词来表达一个概念之后就应该在其它地方继续使用该单词来表达该概念(Pick one word for one abstract concept and stick with it):

    例如表达获取这个动作可以有单词 get, retrive, fetch 等等, 但是如果使用了 get 来表达这个动作, 那么以后就都应该使用 get , 而不要一会儿使用 get, 一会儿又使用 fetch.

  8. 不要使用双关语(Don't Pun):

    例如我们已经使用 add 来表达将两个值加起来或者连接起来, 当需要表达将一个对象放入容器中这个概念时, 就需要重新选择, 例如 insert 或 append 来表达这个概念.(Let’s say we have many classes where add will create a new value by adding or concatenating two existing values. Now let’s say we are writing a new class that has a method that puts its single parameter into a collection. Should we call this method add? It might seem consistent because we have so many other add methods, but in this case, the semantics are different, so we should use a name like insert or append instead. To call the new method add would be a pun)

  9. 尽量选用解决方案领域的名称或者涉及问题领域的名称(Use Solution Domain Names, Use Problem Domain Names)

  10. 添加有意义的语境(Add Meaningful Context):

    public class MeanifulContext {
        static class UnclearContext {
            public static printGuessStatistics(char candidate, int count) {
                // 这些变量没有一个上下文语意
                String number;
                String verb;
                String pluralModifier;
                if (count == 0) {
                    number = "no";
                    verb = "are";
                    pluralModifier = "s";
                } else if (count == 1) {
                    numbers = "1";
                    verb = "is";
                    pluralModifier = "";
                } else {
                    number = Integer.toString(count);
                    ver = "are";
                    pluralModifier = "s";
                }
                String guessMessage = String.format("There %s %s %s%s", verb, number, candidate, pluralModifier);
                System.out.println(guessMessage);
            }
        }
    
        static class GuessStatisticsMessage {
            // 这些变量都属于 GuessStatisticsMessage 这个语意下
            private String number;
            private String verb;
            private String pluralModifier;
    
            public String make(char candidate, int count) {
                createPluralDependentMessageParts(count);
                return String.format("There %s %s %s%s", verb, number, candidate, pluralModifier);
            }
    
            private void createPluralDependentMessageParts(int count) {
                // 这里通过拆分方法来简化代码
                if (count == 0) {
                    thereAreNoLetters();
                } else if (count == 1) {
                    thereIsOneLetter();
                } else {
                    thereAreManyLetters(count);
                }
            }
    
            private void thereAreNoLetters() {
                number = "no";
                verb = "are";
                pluralModifier = "s";
            }
    
            private void thereIsOneLetter() {
                number = "1";
                verb = "is";
                pluralModifier = "";
            }
    
            private void thereAreManyLetters(int count) {
                number = Integer.toString(count);
                verb = "are";
                pluralModifier = "s";
            }
        }
    }
    
  11. 参考:
    [1] : 代码整洁之道