Java接口的防御性API演进

API的发展绝对是不平凡的。 只有少数几个需要处理的事情。 我们大多数人每天都在使用内部专有API。 现代IDE附带了很棒的工具,可以分解,重命名,上拉,下推,间接,委托,推断,泛化我们的代码伪像。 这些工具使重构我们的内部API变得轻而易举。 但是我们中的一些人在公共API上工作,规则在此方面发生了巨大变化。 如果正确完成,则对公共API进行版本控制。 每次更改(兼容或不兼容)都应在新的API版本中发布。 多数人会同意,API升级应在主要版本和次要版本中完成,类​​似于语义版本控制中指定的内容 。 简而言之:不兼容的API更改发布在主要版本(1.0、2.0、3.0)中,而兼容的API更改/增强发布在次要版本(1.0、1.1、1.2)中。

如果您正在计划,那么您将在很长时间内预见到大多数不兼容的更改,然后才实际发布下一个主要版本。 Java中一个早日宣布这种变化的好工具是弃用 。

接口API的演变

现在,弃用是一个很好的工具,它表明您将要从API中删除类型或成员。 如果要在接口的类型层次结构中添加方法或类型怎么办? 这意味着实现您的接口的所有客户端代码都将中断–至少只要尚未引入Java 8的防御方法即可。 有几种技术可以规避/解决此问题:

1.不在乎

是的,这也是一种选择。 您的API是公开的,但使用的程度可能不是很高。 让我们面对现实:并不是我们所有人都在JDK / Eclipse / Apache / etc等代码库上工作。 如果您很友好,则至少要等待主要版本引入新方法。 但是,如果确实需要,您可以打破语义版本控制的规则-如果您可以处理引起一群愤怒的用户的后果。

但是请注意,其他平台并不像Java Universe那样向后兼容(通常是根据语言设计或语言复杂性)。 例如,使用Scala将事物声明为隐式的各种方法,您的API并不总是完美的。

2.用Java方式完成

“ Java”方式根本不发展接口。 JDK中的大多数API类型一直以来都是今天。 当然,这使API感觉很“恐龙化”,并在各种相似类型之间(例如StringBuffer和StringBuilder或Hashtable和HashMap)增加了很多冗余。

请注意,Java的某些部分不遵循“ Java”方式。 最具体地说,JDBC API就是这种情况,它根据第1节“不关心它”的规则演变。

3.用Eclipse的方式来做

Eclipse的内部包含大量API。 在Eclipse中进行开发时, 有很多指导方针如何开发自己的API(即,插件的公共部分)。 关于Eclipse人员如何扩展接口的一个示例是IAnnotationHover类型。 根据Javadoc合同,它允许实现也实现IAnnotationHoverExtension和IAnnotationHoverExtension2 。 显然,从长远来看,这种经过改进的API很难维护,测试和记录文档,最终很难使用! (考虑ICompletionProposal及其6(!)扩展类型)

4.等待Java 8

在Java 8中,您将能够使用防御者方法 。 这意味着您可以为新的接口方法提供明智的默认实现 ,如Java 1.8的java.util.Iterator (摘录)所示:

public interface Iterator<E> {// These methods are kept the same:boolean hasNext();E next();// This method is now made 'optional' (finally!)public default void remove() {throw new UnsupportedOperationException('remove');}// This method has been added compatibly in Java 1.8default void forEach(Consumer<? super E> consumer) {Objects.requireNonNull(consumer);while (hasNext())consumer.accept(next());}
}

当然,您并不总是希望提供默认的实现。 通常,您的界面是必须完全由客户端代码实现的合同。

5.提供公共默认实现

在许多情况下,明智的做法是告诉客户端代码,他们可能需要自己承担实现接口的风险(由于API的发展),因此,他们应该更好地扩展提供的抽象或默认实现。 一个很好的例子是java.util.List ,可能很难正确实现。 对于简单的,对性能不重要的自定义列表,大多数用户可能选择扩展java.util.AbstractList 。 然后剩下剩下要实现的唯一方法是get(int)和size()。所有其他方法的行为都可以从这两个方法中得出:

class EmptyList<E> extends AbstractList<E> {@Overridepublic E get(int index) {throw new IndexOutOfBoundsException('No elements here');}@Overridepublic int size() {return 0;}
}

遵循的一个很好的约定是,如果您的默认实现为AbstractXXX,则将其命名为默认实现;如果是具体的,则将其命名为DefaultXXX

6.使您的API很难实现

现在,这并不是真正的好技术,而只是一个可能的事实。 如果您的API很难实现(一个接口中有100多个方法),则用户可能不会这样做。 注意: 可能 。 永远不要低估疯狂的用户。 一个示例是jOOQ的 org.jooq.Field类型,它表示数据库字段/列。 实际上,这种类型是jOOQ 内部域特定语言的一部分 ,提供了可以在数据库列上执行的各种操作和功能。 当然,拥有太多方法是一个例外,并且-如果您不设计DSL-可能表明整体设计不佳。

7.添加编译器和IDE技巧

最后但并非最不重要的一点是,您可以将一些巧妙的技巧应用于您的API,以帮助人们了解他们应该做些什么,以便正确实现基于接口的API。 这是一个艰难的例子,将API设计人员的意图直接扑向您的脸。 考虑一下org.hamcrest.Matcher API的摘录:

public interface Matcher<T> extends SelfDescribing {// This is what a Matcher really does.boolean matches(Object item);void describeMismatch(Object item, Description mismatchDescription);// Now check out this method here:/*** This method simply acts a friendly reminder not to implement * Matcher directly and instead extend BaseMatcher. It's easy to * ignore JavaDoc, but a bit harder to ignore compile errors .** @see Matcher for reasons why.* @see BaseMatcher* @deprecated to make*/@Deprecatedvoid _dont_implement_Matcher___instead_extend_BaseMatcher_();
}

“友好的提醒” ,来吧。

其他方法

我敢肯定,还有许多其他方法可以开发基于接口的API。 我很好奇您的想法!

参考: JAVA,SQL和ANDOQ博客上的JCG合作伙伴 Lukas Eder 提供了Java接口的防御性API演变 。

翻译自: https://www.javacodegeeks.com/2013/02/defensive-api-evolution-with-java-interfaces.html

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

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

相关文章

sql语句查询各门课程平均分的最大值

解法一&#xff1a; select courseno,stuno,avg(score) 平均分最高值--这里是求平均&#xff0c;后面的条件是过滤最大值的 from tablename group by courseno,stuno having avg(score) > all (select avg(score) sco--这里是过滤最大值 from tablename group by courseno) …

(转)用JS实现表格中隔行显示不同颜色

用JS实现表格中隔行显示不同颜色 第一种&#xff1a; <style> tr{bgColor:expression( this.bgColor((this.rowIndex)%20 )? white : yellow); } </style> <table id"oTable" width"100" border"1" style"border-colla…

Java 系列之spring学习--spring搭建(一)

一、新建maven项目 二、引入spring jar包 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0…

php简单分页,php简单实现分页查询的方法

这篇文章主要为大家详细介绍了php简单实现分页查询的方法&#xff0c;具有一定的参考价值&#xff0c;感兴趣的小伙伴们可以参考一下关于php,最近学了好多&#xff0c;老师跟我们说&#xff0c;现在学的都是php的核心部分&#xff0c;所以我比较注意了一下&#xff0c;也多练习…

Java Collections API怪癖

因此&#xff0c;当涉及到Java Collections API时&#xff0c;我们倾向于认为已经了解了所有内容。 我们知道我们的身边方式列表 &#xff0c; 设置 &#xff0c; 地图 &#xff0c; Iterables &#xff0c; 迭代器 。 我们已经为Java 8的Collections API增强做好了准备。 但是…

笔记 — 动画效果(Css3)

/*** animation-name: 调用 keyframes 所定义的动画* animation-duration: 动画周期所花费的时间长度* animation-timing-function: 规定动画的速度曲线* animation-delay: 延时执行动画的时间* animation-iteration-count: 动画执行的次数* animation-dircetion: 规定动画下一…

可命名元组namedtuple

import collectionsMytupleClass collections.namedtuple(MytupleClass,[x,y,z])objMytupleClass(11,22,33)print(obj.x)print(obj.y)print(obj.z)print(dir(obj))print(help(obj))转载于:https://www.cnblogs.com/POP-w/p/7412278.html

django用户认证系统——登录4

用户已经能够在我们的网站注册了&#xff0c;注册就是为了登录&#xff0c;接下来我们为用户提供登录功能。和注册不同的是&#xff0c;Django 已经为我们写好了登录功能的全部代码&#xff0c;我们不必像之前处理注册流程那样费劲了。只需几分钟的简单配置&#xff0c;就可为用…

php缓存类,PHP缓存类

// ----------------------------------------------------------------------// |缓存类// ----------------------------------------------------------------------// | Author: justmepzy(justmepzygmail.com)// -------------------------------------------------------…

双向@OneToMany / @ManyToOne关联

编程的目标之一是代表现实世界中的模型。 通常&#xff0c;应用程序需要对实体之间的某些关系进行建模。 在上一篇有关Hibernate关联的文章中&#xff0c;我描述了建立“一对一”关系的规则。 今天&#xff0c;我将向您展示如何设置双向的“ 一对多 ”和“ 多对一 ”关联。 这个…

web前端黑客技术揭秘 6.漏洞挖掘

6.1  普通XSS漏洞自动化挖掘思路 6.1.1  URL上的玄机 6.1.2  HTML中的玄机 2.HTML标签之内 6.1.3  请求中的玄机 6.1.4  关于存储型XSS挖掘 6.2.1  HTML与JavaScript自解码机制 <input type"button" id"exec_btn" value"exec" on…

Webpack基础使用

目录 一.什么是Webpack 二.为什么要使用Webpack 三.Webpack的使用 1.下载yarn包管理器 2.Webpack的安装 3.Webpack的简单使用 4.效果 四.Webpack打包流程 一.什么是Webpack Webpack是一个静态模块打包工具 二.为什么要使用Webpack 在开发中&#xff0c;我们常常会遇到…

CSS3及JS媒体查询教程

CSS3媒体查询&#xff1a; 语法&#xff1a; <media_query_list>&#xff1a;<media_query>[,<media_query>] <media_query>&#xff1a;only|not <mediaType> and <expression>[ and <expression>] <expression>&#xff1a;…

php mongodb

// 欄位字串為$querys array("name">"shian");// 數值等於多少$querys array("number">7);// 數值大於多少$querys array("number">array($gt > 5));// 數值大於等於多少$querys array("number">array($…

阿帕奇骆驼遇见Redis

键值商店的兰博基尼 Camel是最好的面包集成框架&#xff0c;在本文中&#xff0c;我将向您展示如何通过利用另一个出色的项目Redis使它更加强大。 Camel 2.11即将发布&#xff0c;具有许多新功能&#xff0c;错误修复和组件。 这些新组件中的几个是我创作的&#xff0c; red…

php 数字加逗号,php数字满三位添加一逗号

//数字满三位添加一逗号&#xff1a;$s_money1 1000000;$s_money2 number_format($s_money1);echo $s_money1;//1000000echo "";echo $s_money2;//1,000,000PHP number_format() 函数number_format() 函数通过千位分组来格式化数字。注释&#xff1a;该函数支持一个…

HTML 教程- (HTML5 标准)摘抄笔记

HTML 教程- (HTML5 标准) 教程网址&#xff1a;http://www.runoob.com/html/html-tutorial.html http://blog.csdn.net/ljfbest/article/details/6700148 HTML版本 从初期的网络诞生后&#xff0c;已经出现了许多HTML版本: 版本发布时间HTML1991HTML 1993HTML 2.01995HTML 3…

spring 隔离级别 测试代码

Controller RequestMapping("/test") Api(value "测试", description "测试") public class TestController {Autowiredprivate TestService testService;RequestMapping(value "listForDirtyRead", method RequestMethod.GET)Res…

他人的一些2017年度总结

闭环思维&#xff1a;自己在做工作的时候&#xff0c;以及在做事情的时候&#xff0c;逐渐养成了闭环思考模式。一个新的东西&#xff0c;一个新的方案&#xff0c;从场景开始梳理&#xff0c;一步步的梳理流程和方案&#xff0c;然后到最终的方案落地&#xff0c;所有的一套流…

Java EE CDI ConversationScoped示例

在本教程中&#xff0c;我们将向您展示如何在Web应用程序中创建和使用ConversationScoped Bean。 在CDI中&#xff0c;bean是定义应用程序状态和/或逻辑的上下文对象的源。 如果容器可以根据CDI规范中定义的生命周期上下文模型来管理其实例的生命周期&#xff0c;则Java EE组件…