设计模式之美——KISS、YAGNI原则

news2024/11/17 3:47:36

在这里插入图片描述
KISS 原则算是一个万金油类型的设计原则,可以应用在很多场景中。它不仅经常用来指导软件开发,还经常用来指导更加广泛的系统设计、产品设计等,比如,冰箱、建筑、iPhone 手机的设计等等。

我们知道,代码的可读性和可维护性是衡量代码质量非常重要的两个标准。而 KISS 原则就是保持代码可读和可维护的重要手段。代码足够简单,也就意味着很容易读懂,bug 比较难隐藏。即便出现 bug,修复起来也比较简单。

下面这三段代码可以实现同样一个功能:检查输入的字符串 ipAddress 是否是合法的 IP 地址。一个合法的 IP 地址由四个数字组成,并且通过“.”来进行分割。每组数字的取值范围是 0~255。第一组数字比较特殊,不允许为 0。


// 第一种实现方式: 使用正则表达式
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 的正则表达本身就比较有挑战;另一方面,并不是每个程序员都精通正则表达式。对于不怎么懂正则表达式的同事来说,看懂并且维护这段正则表达式是比较困难的。这种实现方式会导致代码的可读性和可维护性变差。

第二种实现方式使用了 StringUtils 类、Integer 类提供的一些现成的工具函数,来处理 IP 地址字符串。第三种实现方式,不使用任何工具函数,而是通过逐一处理 IP 地址中的字符,来判断是否合法。从代码行数上来说,这两种方式差不多。但是,第三种要比第二种更加有难度,更容易写出 bug。从可读性上来说,第二种实现方式的代码逻辑更清晰、更好理解。所以,在这两种实现方式中,第二种实现方式更加“简单”,更加符合 KISS 原则。

尽管第三种实现方式性能更高些,但是第三种实现方式实际上是一种过度优化。除非 isValidIpAddress() 函数是影响系统性能的瓶颈代码,否则,这样优化的投入产出比并不高,增加了代码实现的难度、牺牲了代码的可读性,性能上的提升却并不明显。

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

这段KMP 字符串匹配算法代码完全符合我们刚提到的逻辑复杂、实现难度大、可读性差的特点,但它并不违反 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;
}

字符串匹配是某个产品的核心功能(比如 Vim、Word 等文本编辑器),又或者字符串匹配算法是系统性能瓶颈的时候。我们就应该选择尽可能高效的 KMP 算法。而 KMP 算法本身具有逻辑复杂、实现难度大、可读性差的特点。本身就复杂的问题,用复杂的方法解决,并不违背 KISS 原则。

在这里插入图片描述

YAGNI 原则

YAGNI 原则的英文全称是:You Ain’t Gonna Need It。直译就是:你不会需要它。这条原则也算是万金油了。当用在软件开发中的时候,它的意思是:不要去设计当前用不到的功能;不要去编写当前用不到的代码。实际上,这条原则的核心思想就是:不要做过度设计。

YAGNI 原则跟 KISS 原则并非一回事儿。KISS 原则讲的是“如何做”的问题(尽量保持简单),而 YAGNI 原则说的是“要不要做”的问题(当前不需要的就不要做)。


今天的内容有一些哲学味道,让我想到奥卡姆剃刀原理:
如无必要,勿增实体。

用同事不懂的技术,增加了整个团队的理解成本;重复造轮子和过度优化,大多数情况下带来的便利小于增加的成本;
不要写炫技的代码,就像杜峰(CBA广东队教练)说的:“如果没有目的,就不要运球。(因为运球就可能丢球)”,降低出错的概率是一个数学问题,它能够真实得提高软件质量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/31399.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ASIFT算法过程实现 --- 配置避坑指南

常规的SIFT算法进行图像匹配的时候,只能进行两个摄像机夹角比较小的(最大是15),拍摄的图像进行相机的图像匹配,但是针对于相机之间的夹脚比较大的时候,上述的算法匹配就是会出现问题.为了解决上面的这个问题,使用了一种改进的算法匹配方式ASIFT算法进行匹配.具体这种算法的优点…

MYSQL进阶(2)

删除索引:drop Index indexName on tableName; B树叶子结点和非叶子节点都存在数据&#xff0c;那么当数据量很大的时候&#xff0c;把索引加载起来就需要很长时间 联合索引: 1)定义:是给一张表上面的多个列增加索引&#xff0c;也就是说给表上面的多个列增加索引&#xff0c;供…

MongoDB聚集分析

文章目录 聚集操作管道模式聚集MapReduce 聚集简单聚集函数小结聚集操作 聚集操作是对数据进行分析的有效手段。MongoDB 主要提供了三种对数据进行分析计算的方式:管道模式聚集分析、MapReduce聚集分析、简单函数和命令的聚集分析。 管道模式聚集 这里所说的管道类似于UNIX…

2022 APMCM亚太数学建模竞赛 C题 全球是否变暖 思路及代码实现(持续更新中)

2022 APMCM亚太数学建模竞赛 C题 全球是否变暖 思路及代码实现(持续更新中) 1 题目 全球变暖与否? 加拿大49.6C的高温为地球北纬50以上地区创造了新的气温记录&#xff0c;一周内就有数百人死于高温;美国加利福尼亚州死亡谷54.4C&#xff0c;是地球上有记录以来的最高温度;科…

Ubuntu 16.4虚拟机 配置Hadoop集群

Ubuntu 16.4 配置Hadoop集群总体步骤环境说明虚拟机配置java安装hadoop安装与配置克隆虚拟机ssh安装使用&#xff0c;免密登录更改hadoop配置结束语总体步骤 1、虚拟机配置 2、java安装 3、hadoop下载配置 4、复制虚拟机 5、ip更换&#xff0c;使用固定ip&#xff0c;并且每台…

Linux基本指令集合

Linux基本指令1&#xff0c;ls命令2&#xff0c;pwd命令3&#xff0c;whoami4&#xff0c;cd命令5&#xff0c;touch命令6&#xff0c;mkdir命令7&#xff0c;rmdir与rm命令8&#xff0c;man命令9&#xff0c;cp命令10&#xff0c;tree命令11&#xff0c;mv命令12&#xff0c;c…

智慧城市的发展趋势

智慧城市&#xff0c;是指在城市发展过程中&#xff0c;在城市基础设施、资源环境、社会民生、经济产业、市政治理领域中&#xff0c;充分利用物联网、互联网、云计算、IT、智能分析等技术手段&#xff0c;对城市居民生活工作、企业经营发展和政府行政管理过程中的相关活动&…

HTML学生个人网站作业设计:我的家乡网站设计——南宁留言表单 无js 页面8个

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 家乡旅游景点 | 家乡民生变化 | 介绍自己的家乡 | 我的家乡 | 家乡主题 | HTML期末大学生网页设计作业 HTML&#xff1a;结构 CSS&#xff1a;样式 在…

泰克/Tektronix A622电流探头型号规格参数介绍

Tektronix/泰克电流探头A622产品介绍 品牌&#xff1a;Tektronix 产地&#xff1a;美国 Tektronix泰克A622交直流电流探头适用于万用表和示波器钳型;通用BNC接口。 Tektronix/泰克电流探头A622产品特点&#xff1a; AC/DC-100kHz 50mA to 100A峰值 适用于万用表和示波器 钳形开…

HTML期末大学生网页设计作业——奇恩动漫HTML (1页面) HTML+CSS+JS网页设计期末课程大作业

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 ⚽精彩专栏推荐&#x1…

C++:函数:回调函数:还不懂回调函数来捶我

前言 不知道你是否有这样的疑问&#xff0c;我们为什么需要回调函数&#xff0c;直接调用函数不就可以了吗&#xff1f;回调函数到底有什么用&#xff1f;程序员该如何理解回调函数了&#xff1f; 这篇文章就为你解答这些问题&#xff0c;读完这篇文章后&#xff0c;你的编程…

连接肠菌与宿主的桥梁:肠菌代谢物——肠菌功能研究新篇章

人的肠道内寄居着多种微生物&#xff0c;他们统称为肠道菌群。研究表明&#xff0c;肠道菌群失衡会导致多种人体疾病&#xff0c;包括糖尿病、肿瘤、心血管疾病、神经系统疾病等。 那么肠菌是怎么对人产生影响的呢&#xff1f;答案是肠菌产生的代谢物&#xff08;1, 2&#xf…

Vue3+nodejs全栈项目(资金管理系统)——后端篇(一)登录、注册

文章目录初始化创建项目配置跨域配置解析表单数据的中间件安装bodyparser初始化用户路由模块抽离用户路由模块中的处理函数登录注册新建admin表安装并配置mysql模块注册检测表单数据是否合法检测用户名是否被占用对密码进行加密处理bcryptjs插入新用户测试登录根据名字查询用户…

CDH6.3.2处理Zookeeper因未授权访问造成的漏洞

1.zookeeper的基本情况 zookeeper是分布式协同管理工具&#xff0c;常用来管理系统配置信息&#xff0c;提供分布式协同服务。zookeeper官网下载软件包&#xff0c;bin目录下有客户端脚本和服务端脚本。另外还有个工具对理解和使用zookeeper服务非常有用&#xff0c;即zk-ui&am…

文本层次语义元素

html5-文本层次语义元素 第1关_文本层次语义元素相关概念 第2关_文本层次语义元素 编程要求 在右侧编辑器中的Begin - End区域内补充代码&#xff0c;具体要求是&#xff1a; 1.运用HTML5中的语义化元素设计一个文章区(<article>)。 2.文章区中的头部为文章的标题&a…

如何自己开传奇单机架设超详细图文教程

如何自己成为传奇&#xff0c;如何自己搭建传奇非官服&#xff0c;首先下载传奇服务器后&#xff0c;会有两个压缩包&#xff0c;一个用于服务器&#xff0c;一个用于游戏补丁文件 传奇单机设置-GOM引擎的超详细图文教程 版本文件包含.exe&#xff0c;以上文件都不起作用。 …

共享里的文件被删除了怎么办?可尝试这三种恢复方法

共享里的文件被删除了怎么恢复&#xff1f;删除之后就马上去回收站找&#xff0c;可是没回收站里没有怎么办&#xff1f;——来自某xx小伙伴的咨询。如果你也出现同样的疑惑&#xff0c;那么可以尝试下面的三种方法恢复共享里的文件。 方法一、以前的版本恢复 从Windows XP SP…

前端获取ip地址判断国家请求不同baseUrl

项目背景 项目新需求&#xff1a;根据ip地址区分出国内外上网&#xff0c;axios 使用不同的baseurl&#xff0c;上传阿里oss不同bucket 获取ip地址 一、使用js自己获取 使用 RTCPeerConnection.setLocalDescription() WebRTC API pc端没问题&#xff0c;移动端不好使 //获取…

react源码分析:深度理解React.Context

开篇 在 React 中提供了一种「数据管理」机制&#xff1a;React.context&#xff0c;大家可能对它比较陌生&#xff0c;日常开发直接使用它的场景也并不多。 但提起 react-redux 通过 Provider 将 store 中的全局状态在顶层组件向下传递&#xff0c;大家都不陌生&#xff0c;…

第十期|惊!游戏广告主投放十万被骗,推广作弊竟全是虚拟用户

顶象防御云业务情报中心发现&#xff0c;在互联网生态中存在很多灰色的渠道刷量工作室&#xff0c;渠道方通常以低廉的价格通过这些工作室提高广告URL点击量、应用下载激活量、注册量和真实的推广数据提起反馈给广告主结算&#xff0c;但其提供的数据质量和价格一样低廉&#x…