竹笋

注册

 

发新话题 回复该主题

我去头条面试,面试官问我如何设计好API [复制链接]

1#
北京的最好白癜风医院 http://www.znlvye.com/m/

来源

Java开发宝典(ID:javakaifabaodian)

头图

CSDN下载自东方IC

语言首先是写给人看的,只是恰巧(incidentally)能够运行——《计算机程序的构造和解释》。

好的API应对客户端友好,换言之就是能够直接通过其方法签名而理解它做的事情,而不用深入去阅读方法的实现,甚至深入阅读API所在的整个类。

单纯的介绍如何设计好API似乎如海市蜃楼般的虚无缥缈,因此本文从设计实现的角度出发,针对我们在设计并实现API的过程中提出一些小意见。

首先回顾一下API方法的组成模块:

API注释访问修饰符返回值方法名称参数列表异常列表方法主体针对API方法的组成模块,将提出几点小意见;可简单归纳为:一个原则,三点建议,两个思考,三要五不要。

一原则

最小知识原则(LeastKnowledgePrinciple)

最小知识原则,或称迪米特法则;是一种面向对象程序设计的指导原则,它描述了一种保持代码松耦合的策略。

它描述的是一个软件实体应尽可能少地与其他实体发生相互作用;这里的软件实体是一个广义的概念,可指代系统、类、模块、对象、函数、变量等。

用更加通俗的语言来描述就是:“不应该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口”。(“软件实体”替换成“类”)

用一个例子来描述,DatabaseConfig类为数据库实体类,用以描述数据源信息;JdbcUtils类用以封装一些基础的JDBC操作。

/***数据库实体对象*

date/9/6**/

Data

Builder

NoArgsConstructor

AllArgsConstructorpublicclassDatabaseConfig{privatelongid;privateintclusterId;privateStringhost;privateStringport;privateStringdbName;privateStringdbType;privateStringjdbcUrl;privateStringusername;privateStringpassword;privateStringdbOwner;privateStringcreateUser;privateStringupdateUser;privateStringcreateTime;privateStringupdateTime;}/***jdbc底层操作*执行SQL包装数据等*

date/9/6**/publicclassJdbcUtils{//获取jdbcConnectionpublicstaticConnectiongetConnection(

NonNullDatabaseConfigdatabaseConfig)throwsClassNotFoundException,SQLException{DbTypedbType=DbType.valueOf(databaseConfig.getDbType());Class.forName(dbType.getDriver());returnDriverManager.getConnection(databaseConfig.getJdbcUrl(),databaseConfig.getUsername(),databaseConfig.getPassword());}}

这段代码虽然能满足业务需求,但有些地方可以做到更好。JdbcUtils作为一个底层的基础服务类,希望做到尽可能的通用,而不只是支持DatabaseConfig数据源;其次从另外一个角度来看,DatabaseConfig实体中有太多的属性字段,getConnectionAPI到底依赖哪个字段难以确认;所以getConnectionAPI的设计一定程度上违背了最小知识原则,依赖了不该有的直接依赖关系的DatasourceConfig类。

我们可对JdbcUtils的getConnection方法作以改造,使其满足最小知识原则。我们应该只提供getConnection需要的信息。

publicstaticConnectiongetConnection(

NonNullStringdriver,

NonNullStringjdbcUrl,

NonNullStringusername,

NonNullStringpassword)throwsClassNotFoundException,SQLException{Class.forName(driver);returnDriverManager.getConnection(jdbcUrl,username,password);}

最小知识原则希望减少类之间的耦合,让类越独立越好。每个类都应该少了解系统中其他部分,这样一旦其他部分发生变化,自身就不会受到影响,避免了“城门失火,殃及池鱼”的发生。

三建议

1.建议优先使用接口而不是具体实现类

优先使用接口类型作为API的返回值类型或参数类型,有利于提升API的可扩展性。这同时也是设计原则——依赖倒置原则所提倡的。

例如,上面例子中的DataSourceConfig数据源需要加密,应该使用Encryptor加密器接口,而不是具体的KeyCenterEncryptor加密器类;因为随着业务的发展,很有可能出现新的加密类型,使用KeyCenterEncryptor加密器类对会使得难以扩展新的加密类型。

/***加密器*

date/9/6**/publicinterfaceEncryptor{/***加密*

paramstr待加密字符串*

returnString加密后的字符串*/publicStringencrypt(Stringstr);}/***keyCenter加密器*

date/9/6**/publicclassKeyCenterEncryptorimplementsEncryptor{

OverridepublicStringencrypt(Stringstr){//...//执行keyCenter加密return}}

2.善于利用枚举类型实际的开发场景中,需求在不断的变更迭代,善于利用枚举类型有利于留有余地的处理多样化的需求。并且枚举类型有着简洁、易读、可扩展的优点。

例如,上面所提到的加密类型,可以提供一个枚举类型用于描述。

/***加密类型枚举类*

date/9/6*/

Getter

AllArgsConstructorpublicenumEncryptTypeEnum{/***加密类型*/KEY_CENTER(0,keyCenter加密),MD5(1,MD5加密)//后续扩展新的加密类型....;privatefinalintcode;privatefinalStringdesc;}

3.统一API命名规则API的命名应该遵循标准的命名规则,应该选择易于理解,并与同一个包中其他命名风格一致的名称,避免使用长的方法名称;具体可参考《阿里巴巴开发手册》的命名规范。例如:对于具有查询含义的API,可以以queryXXX来命名。

两思考

1.是否使用Optional?

Optional容器是JAVA8提出的用以解决臭名昭著的空指针异常(NullPointerException)的一次尝试,当我们在编写某些无返回值的API方法时,Optional的出现提供了一种新的选择方案。但这并不意味着无返回值的API方法都应该使用Optional返回。

在遇到无返回值的时候,通常我们有3种选择方案:1.抛异常2.返回null3.返回Optional;实际开发中我们应该选择哪种方案合适呢?或许可以从以下几点做出判断:

Optional的思想和受检异常(CheckedException)类似,它强迫客户端面对可能没有返回值的事实,而抛出未受检异常(UnCheckedException)或者返回null没有显式的指明这一点,客户端可能会因忽略这一可能性而产生一些意想不到的后果。

如果API方法可能无法返回结果,并且在无返回结果的时候,客户端还必须执行特殊处理的情况下,应尝试返回Optional。

Optional是必须分配空间和初始化对象的,从Optional中读取值(value)也需要额外的处理;因此如果API方法有很明显的性能上的要求,不建议使用Optional。

下面可以看一个例子:

/***用accessToken换取用户信息*

paramaccessToken*

returnUserInfo*/publicOptionalUserInfogetProfile(StringaccessToken){if(StringUtils.isEmpty(accessToken)){log.warn(token为空,无法根据token获取userProfile);returnOptional.empty();}Stringurl=OauthConstant.CAS_URL+/oauth2.0/profile?access_token=+accessToken;try{//发送
分享 转发
TOP
发新话题 回复该主题