zoukankan      html  css  js  c++  java
  • 设计模式简记-设计原则之KISS原则

    3.6 KISS原则

    3.6.1 如何理解KISS原则?

    • KISS 原则的英文描述有好几个版本:

      • Keep It Simple and Stupid.
      • Keep It Short and Simple.
      • Keep It Simple and Straightforward.

      意思其实差不多,翻译成中文就是:尽量保持简单。

    3.6.2 代码行数越少就越“简单”吗?

    • 例子:三段代码可以实现同样一个功能:检查输入的字符串 ipAddress 是否是合法的 IP 地址。

      // 第一种实现方式: 使用正则表达式
      public boolean isValidIpAddressV1(String ipAddress) {
        if (StringUtils.isBlank(ipAddress)) return false;
        String regex = "^(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|[1-9])\."
                + "(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\."
                + "(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\."
                + "(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)$";
        return ipAddress.matches(regex);
      }
      
      // 第二种实现方式: 使用现成的工具类
      public boolean isValidIpAddressV2(String ipAddress) {
        if (StringUtils.isBlank(ipAddress)) return false;
        String[] ipUnits = StringUtils.split(ipAddress, '.');
        if (ipUnits.length != 4) {
          return false;
        }
        for (int i = 0; i < 4; ++i) {
          int ipUnitIntValue;
          try {
            ipUnitIntValue = Integer.parseInt(ipUnits[i]);
          } catch (NumberFormatException e) {
            return false;
          }
          if (ipUnitIntValue < 0 || ipUnitIntValue > 255) {
            return false;
          }
          if (i == 0 && ipUnitIntValue == 0) {
            return false;
          }
        }
        return true;
      }
      
      // 第三种实现方式: 不使用任何工具类
      public boolean isValidIpAddressV3(String ipAddress) {
        char[] ipChars = ipAddress.toCharArray();
        int length = ipChars.length;
        int ipUnitIntValue = -1;
        boolean isFirstUnit = true;
        int unitsCount = 0;
        for (int i = 0; i < length; ++i) {
          char c = ipChars[i];
          if (c == '.') {
            if (ipUnitIntValue < 0 || ipUnitIntValue > 255) return false;
            if (isFirstUnit && ipUnitIntValue == 0) return false;
            if (isFirstUnit) isFirstUnit = false;
            ipUnitIntValue = -1;
            unitsCount++;
            continue;
          }
          if (c < '0' || c > '9') {
            return false;
          }
          if (ipUnitIntValue == -1) ipUnitIntValue = 0;
          ipUnitIntValue = ipUnitIntValue * 10 + (c - '0');
        }
        if (ipUnitIntValue < 0 || ipUnitIntValue > 255) return false;
        if (unitsCount != 3) return false;
        return true;
      }
      
      • 第一种实现方式利用的是正则表达式。虽然代码行数最少,看似最简单,实际上却很复杂。这正是因为它使用了正则表达式:
        • 一方面正则表达式本身是比较复杂的,写出完全没有 bug 的正则表达本身就比较有挑战;
        • 另一方面,并不是每个程序员都精通正则表达式。对于不怎么懂正则表达式的同事来说,看懂并且维护这段正则表达式是比较困难的。
        • 这种实现方式会导致代码的可读性和可维护性变差,所以,从 KISS 原则的设计初衷上来讲,这种实现方式并不符合 KISS 原则。
      • 第二种实现方式使用了 StringUtils 类、Integer 类提供的一些现成的工具函数,来处理 IP 地址字符串:
      • 第三种实现方式,不使用任何工具函数,而是通过逐一处理 IP 地址中的字符,来判断是否合法。
      • 从代码行数上来说,这两种方式差不多。但是,第三种要比第二种更加有难度,更容易写出 bug。从可读性上来说,第二种实现方式的代码逻辑更清晰、更好理解。所以,在这两种实现方式中,第二种实现方式更加“简单”,更加符合 KISS 原则。
      • 第三方实现方式性能可能更好,但属于过度优化,除非这个功能成为性能瓶颈,否则这样的优化投入产出比不高。

    3.6.3 代码逻辑复杂就违背 KISS 原则吗?

    // KMP algorithm: a, b分别是主串和模式串;n, m分别是主串和模式串的长度。
    public static int kmp(char[] a, int n, char[] b, int m) {
      int[] next = getNexts(b, m);
      int j = 0;
      for (int i = 0; i < n; ++i) {
        while (j > 0 && a[i] != b[j]) { // 一直找到a[i]和b[j]
          j = next[j - 1] + 1;
        }
        if (a[i] == b[j]) {
          ++j;
        }
        if (j == m) { // 找到匹配模式串的了
          return i - m + 1;
        }
      }
      return -1;
    }
    
    // b表示模式串,m表示模式串的长度
    private static int[] getNexts(char[] b, int m) {
      int[] next = new int[m];
      next[0] = -1;
      int k = -1;
      for (int i = 1; i < m; ++i) {
        while (k != -1 && b[k + 1] != b[i]) {
          k = next[k];
        }
        if (b[k + 1] == b[i]) {
          ++k;
        }
        next[i] = k;
      }
      return next;
    }
    

    以上为字符串匹配算法KMP算法实现代码,当字符串匹配是某个产品的核心功能,或这部分功能为性能瓶颈的时候,就应该选择高性能的复杂的算法。

    • 本身就复杂的问题,用复杂的方法解决,并不违背 KISS 原则。

    3.6.4 如何写出满足 KISS 原则的代码?

    • 不要使用同事可能不懂的技术来实现代码。比如前面例子中的正则表达式,还有一些编程语言中过于高级的语法等。
    • 不要重复造轮子,要善于使用已经有的工具类库。经验证明,自己去实现这些类库,出 bug 的概率会更高,维护的成本也比较高。不要过度优化。
    • 不要过度使用一些奇技淫巧(比如,位运算代替算术运算、复杂的条件语句代替 if-else、使用一些过于底层的函数等)来优化代码,牺牲代码的可读性。

    3.6.5 YAGNI 跟 KISS 说的是一回事吗?

    • YAGNI 原则的英文全称是:You Ain’t Gonna Need It。直译就是:你不会需要它。
    • 核心思想就是:不要做过度设计
    • 比如,系统暂时只用 Redis 存储配置信息,以后可能会用到 ZooKeeper。根据 YAGNI 原则,在未用到 ZooKeeper 之前,没必要提前编写这部分代码。这并不是说就不需要考虑代码的扩展性。还是要预留好扩展点,等到需要的时候,再去实现 ZooKeeper 存储配置信息这部分代码。
    • KISS 原则讲的是“如何做”的问题(尽量保持简单),而 YAGNI 原则说的是“要不要做”的问题(当前不需要的就不要做)。
  • 相关阅读:
    软工5--结对2--四则运算生成器
    软工4——结对审查
    天数计算器
    翻转字符串
    位图排序
    软工 assignment 3 —— 求最大子数列之和
    剑指offer 面试题5.替换空格
    剑指offer 面试题4.二维数组中的查找
    剑指offer 面试题3.数组中重复的数字
    如何通过onenote发送博客到cnblog(博客园)
  • 原文地址:https://www.cnblogs.com/wod-Y/p/12762840.html
Copyright © 2011-2022 走看看