背景
在企业中,一个对外发布的产品一般会涉及到好几个部门、不同人员开发的系统。
每个部门甚至每个人开发的系统的返回码体系可能都是不一样的,比如:
- A系统把系统返回码都放在SystemAResultCode的枚举类中
- B系统则把系统返回码都放在SystemBResultCode的枚举类中
- 等等
系统间不同的返回码会造成:
- 无法设计通用响应数据结构。在rpc调用场景,这一点很重要;
- 无法互操作。当需要对返回码组织层级关系时,需要直接操作被调用方返回的返回码。
目标
- 可扩展:随着业务发展,返回码肯定处于一个膨胀的过程。设计时给各个业务系统保留扩展能力;
- 互联互通互操作:系统之间的返回码要能够互通。我能够读取你的返回码,你也得认我的返回码;
- 能够定义基础行为:如统一加系统、业务标识或者定义返回码之间的继承逻辑。
实现
系统中的返回码一般都会设计成一个枚举类,枚举类有天然的好处:
- 集中管理,系统中有哪些返回码一目了然
- 枚举实例可以通过名称进行自解释
- 枚举实例被final修饰不能被重新赋值,避免运行过程中被修改
- 等等
但是这里有一个问题:枚举不能被继承
这个语法规范直接把设计一个父枚举,各个系统去继承该父枚举
的想法扼杀在摇篮中。
有没有其他办法了呢?答案是有的:
利用枚举可以实现接口的特点,定义一个返回码行为接口,各个系统的返回码枚举类实现该接口即可。
甚至可以利用Java8的特性,在接口中定义default方法来描述返回码的组织关系,如:
- 隔离系统间的返回码,避免重复;
- 定义返回码之间的继承行为等。
example
/**
* 各个应用方应当实现本接口,以实现自定义的返回值
* @see DefaultResultCode
*
* @author liumian 2020/3/2 2:22 下午
*/
public interface ResultCode {
/**
* 获取返回码
*
* @return resultCode
*/
String getCode();
/**
* 获取简单的说明
*
* @return resultMsg
*/
String getMsg();
/**
* 获取系统码,用于区分系统
*
* @return 系统码
*/
String getSysCode();
/**
* 获取全局的返回码,系统间不会重复
*
* @return 全局返回码
*/
default String getFullCode(){
return getSysCode()+"-"+getCode();
}
}
public enum DefaultResultCode implements ResultCode{
/**
* 成功
*/
Success("000001","success");
private String code;
private String msg;
DefaultResultCode(String code, String msg) {
this.code = code;
this.msg = msg;
}
@Override
public String getCode() {
return code;
}
@Override
public String getMsg() {
return msg;
}
@Override
public String getSysCode() {
return "default";
}
}
拥有了统一的返回码,那么设计一个通用的响应消息数据结构也变得比较轻松了。
通过这个例子,让我再次感受到类设计和接口设计上的思维差异:
- 接口更多的是用来描述行为(能干什么),不关心具体的数据以及实现逻辑;
- 而类设计则用来描述实体之间层次结构以及内部的数据和状态(是什么)。