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 原则说的是“要不要做”的问题(当前不需要的就不要做)。
  • 相关阅读:
    ECharts之柱状图 饼状图 折线图
    Vue自定义指令(directive)
    HDU 1231 最大连续子序列
    POJ 2533 Longest Ordered Subsequence
    HDU 1163 Eddy's digital Roots
    HDU 2317 Nasty Hacks
    HDU 2571 命运
    HDU 4224 Enumeration?
    HDU 1257 最少拦截系统
    HDU 2740 Root of the Problem
  • 原文地址:https://www.cnblogs.com/wod-Y/p/12762840.html
Copyright © 2011-2022 走看看