概述
本文是继《编写代码的「八荣八耻」(上篇)》和《编写代码的「八荣八耻」-以开关上线为荣,以自信编码为耻 》之后,编写代码的「八荣八耻」系列的第三篇。
本篇整体框架还是采用经典的问题分析三步曲:what、why、how。
WHAT
编写代码的「八荣八耻」
1. 产品命名:以简单有趣为荣,以平庸难记为耻。
2. 单个方法:以短小精悍为荣,以冗长费神为耻。
3. 代码维护:以持续重构为荣,以停滞不前为耻。
4. 编程思想:以面向对象为荣,以面向过程为耻。
5. 程序设计:以开关上线为荣,以自信编码为耻。
6. 接口定义:以用户易用为荣,以复杂歧义为耻。
7. 断言分支:以实时报警为荣,以忽略分支为耻。
8. 报警策略:以定时调整为荣,以放弃维护为耻。
WHY
面向对象的设计中,之所以要抽象成接口,而不直接面向实现类。主要是基于「抽象比细节更长久」的理论基础,实现类可更改可替换。
调用方不需要关心接口怎么实现,只需要知道接口做什么和怎么用即可。这也注定了接口设计的两个基本指标:易懂和易用。
HOW
这里主要针对平时工作中看到的同学经常犯的三个误区做建议。
-
以包罗万象为耻
-
以需传默认为耻
-
以按业务定义为荣,以按技术定义为耻。
来看一下出现这个三个误区的影响三叶草:
从图中可以看出,出现这三个误区,最终会产出难懂又难用的烂接口。下面针对这三个方面给出具体的例子。
以包罗万象为耻
Elasticsearch(ES)很强大,支持很多复杂查询。做了一个查询系统,底层用了ES做存储。提供接口给上层调用。如果直接把ES接口作为自己的业务接口给上层来调用,这会很强大,想查的东西一定可以查到。但是请回家路上小心点,很可能第二天就看不到你来上班了,因为被做上层的同事给打死了。
比较好的一个实践是针对上层调用方的具体需求,产生出一个更加有针对性的接口。有很简单的入参和出参。比如ES里存的是世界地图。上层调用方是做定位的。他会输入两个参数:经度和纬度。他只需要返回一个信息:所在城市。那就自己封装好给调用方提供一个根据经纬度查询城市的接口就好了。
以需传默认为耻
这个很好理解。下面是java.lang.String类的构造方法。如果不提供只有char入参的,每次调用都需要填写默认的new String('f',-1,2),是不是很想砍人?
最悲催的是这种形式的调用:
Shit shit = crap.shit("shit",null,null,null,null,null,null);
数null数到头晕。底层封装一层撒。
以按业务定义为荣,以按技术定义为耻
其实静儿在写代码的时候经常写这样一种实现:定义一个XXXBuilder,入参是一个XXXXOption类。这是一种常见的设计模式。将各种选项放到构造器里构造出真正需要的入参。然后再交给一个接口让它去完成功能。构造入参代码举例如下:
是不是很头大?作为基础接口提供者,需要将这些复杂的技术逻辑封装好成业务领域的接口。实在是逻辑复杂也要自己提供静态的Builder工具让客户端可方便的合成。不要把这些任务交给调用方自己去完成。
上面一堆代码可以通过「策略下沉」将其抽象为一种策略,打个比方定义为:通用宿主机正常状态选项。把这个选项做成封装暴露出去,不是直接让调用方来拼这个入参。
总结
少即是多
温故知新