svn: 没有演进历程信息_使用默认方法的接口演进–第二部分:接口

svn: 没有演进历程信息

引入了默认方法以启用接口演进。 如果向后兼容性是不可替代的,则仅限于向接口添加新方法(这是它们在JDK中的唯一用法)。 但是,如果希望客户端更新其代码,则可以使用默认方法逐步演化接口而不会引起编译错误,从而使客户端有时间将其代码更新为新版本的接口。

这个小型系列的第一部分说明了默认实现如何允许在不破坏客户端代码的情况下添加,替换和删除方法。 我愚蠢地宣布,“以后的文章将探讨替换整个接口的方法”,同时也不会破坏客户端代码。

好吧,您现在正在阅读这篇文章,不幸的摘要是:

我无法使其工作。

为什么? 泛型。

到底为什么 你真的想知道吗 好吧,那么请继续阅读,但是这篇文章的其余部分实际上只是对我如何成为障碍的描述,因此不要期望太多。 (大激励,是吗?)

总览

在描述我尝试过的方法和失败的方法之前,我先定义要解决的问题。

问题陈述

这就是我们要做的:

假定您的代码库包含一个接口,您的客户端可以用所有可以想象的方式使用该接口:它们具有自己的实现,使用其实例调用您的代码,并且您的代码返回此类实例,当然他们将其用作参数的类型和返回值。

现在,您要实质性地更改接口:以无法用对单个方法的更改来表示的方式对其进行重命名,移动或修改。 (但是从提供一个版本到另一个版本的角度来看,这两个接口仍然是等效的。)

您可以执行此操作,发布包含更改的新版本,并告诉您的客户端修复其导致的编译错误。 如果他们的代码与您的代码高度耦合,那么他们可能必须在单独的分支中执行此操作以花一些时间在代码上,但这就是生活,对吗? 不过,您真是个好人,因此,与其要求费时的一天,不如让他们有机会随着时间的推移(例如,直到下一个版本)逐渐更改其代码,而没有任何编译错误。

(请注意,这是接下来所有内容的主要要求。我首先忽略了这是否是个好主意。我只是想看看自己能走多远。)

我认为甚至有机会实现这一目标的唯一方法是定义一个过渡阶段,在该阶段中,新旧版本的接口都将共存。 因此,我们真正需要的是一种通用的逐步方法,该方法如何将实现,调用者和声明从一个接口转移到另一个接口。

想法

在发布这篇文章时,我对它的工作方式有一个具体的想法。 基本上与我在方法中使用的方法相同。

不断发展的接口方法

使用默认方法添加,替换或删除接口的单个​​方法非常简单,通常包括三个步骤(在某些情况下更少):

  • 新版本:库的新版本发布,其中界面定义是过渡性的,并结合了旧的和新的所需轮廓。 默认方法可确保所有外部实现和调用仍然有效,并且在更新时不会出现编译错误。
  • 过渡:然后客户有时间从旧大纲过渡到新大纲。 同样,默认方法可确保适应的外部实现和调用有效,并且可以进行更改而不会产生编译错误。
  • 新版本:在新版本中,该库删除了旧轮廓的残差。 鉴于客户端明智地利用了自己的时间并进行了必要的更改,因此发布新版本不会导致编译错误。

如果您对这些步骤的详细说明感兴趣,可以阅读我的早期文章 。

改进界面

对于这种情况,这种方法似乎也很有意义,所以我坐下来进行了探讨。

如果整个接口发生变化,则要稍微复杂一点,因为在方法仅具有调用者和实现的地方,该接口也是一种类型,即可以在声明中使用。 这使得必须区分三种使用接口的方式:

  • 内部使用 ,您在其中拥有实现和使用接口的代码
  • 已发布的使用 ,您拥有实现,但客户端调用了代码
  • 外部使用 ,其中客户端拥有实现和使用接口的代码

起作用的部分采用与演化方法相同的方法:

  • 新版本:使用新界面发布新版本,以扩展旧版本。 让所有内部代码实现并使用新接口。 所有已发布的代码将使用旧接口声明参数类型,并使用新接口返回类型。 如果必须转换实例,则可以使用适配器来完成。 现在忽略参数化类型,此更改将不会导致客户端代码中的编译错误。
  • 过渡:发布后,客户端更改其代码。 从旧接口的实现(已更改为实现新接口的实现)和您已发布的代码返回的实例开始,它们可以开始声明新类型的实例,更新将它们传递给它们的方法的参数类型,等等。上。 如有必要,可以暂时使用适配器通过新接口与旧实例进行交互。
  • 新版本:发布一个删除旧界面的版本。

与不断发展的方法相同,新接口中的默认实现允许客户端代码停止明确实现旧接口,从而可以在第二个版本中将其删除。 此外,旧接口上的便捷asNew()方法可以调用适配器以使其自身适应新接口。

我掩饰了一些细节,但我希望你相信我,这是可行的。 现在让我们回到泛型…

障碍

提出的方法中的关键部分是已发布的代码。 它由您的客​​户调用,因此第一个发行版必须以兼容的方式对其进行更改。 并且由于所有内部代码都需要新接口,因此它必须从OldNew

没有泛型,它可能看起来像这样:

在已发布的代码中将“旧”转换为“新”

// in version 0
public Old doSomething(Old o) {// 'callToInternalCode' requires an 'Old'callToInternalCode(o);return o;
}// in version 1 the method still accepts 'Old' but returns 'New'
public New doSomething(Old o) {// 'callToInternalCode' now requires a 'New'New n = o.asNew();callToInternalCode(n);return n;
}

好的,到目前为止很好。 现在,让我们看看泛型的外观。

在已发布的代码中将“旧”转换为“新” –泛型

// in version 0
public Container<Old> doSomething(Container<Old> o) {// 'callToInternalCode' requires a 'Container<Old>'callToInternalCode(o);return o;
}// in version 1
// doesn't work because it breaks assignments of the return value
public Container<New> doSomething(Container<Old> o) {// 'callToInternalCode' requires a 'Container<New>'// but we can not hand an adapted version to 'callToInternalCode'// instead we must create a new containerNew nInstance = o.get().asNew();Container<New> n = Container.of(nInstance);callToInternalCode(n);return n;
}

因此,使用已发布的代码层从旧界面适应新界面通常不起作用,原因至少有两个:

  • 由于Java中泛型的不变性,返回值的所有分配都将中断:

    不变性打破分配
    Container<Old> old = // ...
    // works in version 0; breaks in version 1
    Container<Old> o = published.doSomething(old);
  • 不能将同一Container实例从已发布传递到内部代码。 这导致两个问题:
    • 创建一个新容器可能很困难或不可能。

该死的…

由华盛顿州交通运输部根据CC-BY-NC-ND 2.0发布。

发布时间由交通运输的华盛顿州部门在CC-BY-NC-ND 2.0 。

从一开始,我就感到仿制药会很麻烦-回想起来,这实际上很明显。 当涉及类型时,泛型怎么可能不是问题。 因此,也许我应该先尝试解决难题。

可能绕行

在将我的头撞在墙上一段时间之后,我仍然没有找到解决这个问题的通用方法。 但是我想出了一些可能有助于解决特殊情况的想法。

通配符

您可以检查已发布的内部代码是否充分利用了通配符(请记住PECS )。 您也可以建议客户如何使用它们。

根据情况,这可能会产生解决方案。

专用接口,类,实例

根据具体的代码,可以提供使用旧接口的已发布接口,类或实例的新版本。 如果可以通过让客户端选择使用依赖于旧接口的接口,类或实例还是依赖于新接口的接口,类或实例的方式来处理代码,则各个实现不必进行转换。

但这可能会将旧界面推回内部代码,而内部代码刚刚更新为仅使用新接口。 听起来也不好。

容器适配器

您可以在已发布的代码中为与旧接口一起使用的容器提供适配器。 这实际上将允许您在这些容器上调用asNew()

(出于一个不相关的原因,我目前正在为某些JDK集合进行此类转换。下一版本的LibFX将包含它们;如果您好奇,可以在GitHub上查看演示。)

算了!

这一切又是为了什么? 为了防止客户创建分支,在将所有内容合并回master之前花一些时间在那里修复问题吗? 算了!

在这一点上,这是我对此事的看法。 只要您只处理单个方法,接口的演变就很顺利,但是当您要替换整个接口时,这似乎会很痛苦。 因此,除非有充分的理由介绍所有这些复杂性,否则我将以困难的方式进行操作,然后让客户对其进行分类。 还是根本不做。

而且,如果您只是重命名或移动界面,无论如何,大部分甚至全部工作都可以通过简单的搜索替换来完成。

反射

我们重申了如何将默认方法用于发布,过渡和发布三部分的界面演化。 尽管这对单个方法有效,但我们发现它无法替换整个接口。 主要问题是参数类型的不变性使我们无法使用已发布的代码作为适应层。

即使我们看到了一些解决该问题的方法,也没有一个好的解决方案脱颖而出。 最后,看起来不值得麻烦。

我有事吗 还是整个想法愚蠢? 为什么不发表评论!

翻译自: https://www.javacodegeeks.com/2015/04/interface-evolution-with-default-methods-part-ii-interfaces.html

svn: 没有演进历程信息

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

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

相关文章

蓝桥杯7届c语言 c组答案,第七届蓝桥杯C语言C组-(自己懂的题目)

第七届蓝桥杯C语言C组-(自己懂的题目)表示刚刚查了成绩&#xff0c;省赛一等奖&#xff0c;有资格去北京了&#xff0c;然后写一下总结&#xff0c;先来写一下我懂的题目&#xff0c;毕竟我也是菜鸟&#xff0c;听说国赛比预赛难几个等级。。。第一题报纸页数X星球日报和我们地…

关于多线程的几道面试题

点击蓝字关注我们第一题&#xff1a;线程的基本概念、线程的基本状态及状态之间的关系&#xff1f;线程&#xff0c;有时称为轻量级进程&#xff0c;是CPU使用的基本单元&#xff1b;它由线程ID、程序计数器、寄存器集合和堆栈组成。它与属于同一进程的其他线程共享其代码段、数…

c语言 想输入非数字是报错误,C语言上机练习5C言上机练习5.doc

C语言上机练习5C言上机练习5C语言上机报告5 数组2上机内容找出下列程序中的错误并改正1) /*有一个34的矩阵,要求输出其中值最大的元素的值,以及它的行号和列号。*/#include "stdio.h"#define M 3//无分号#define N 4void main( ){ int max,i,j,r,c;int a[M][N]{{323…

大牛谈嵌入式C语言的高级用法

点击蓝字关注我们内存管理我们需要知道——变量&#xff0c;其实是内存地址的一个抽像名字罢了。在静态编译的程序中&#xff0c;所有的变量名都会在编译时被转成内存地址。机器是不知道我们取的名字的&#xff0c;只知道地址。 内存的使用时程序设计中需要考虑的重要因素之一&…

java转换为c#_C#vs Java哪一个更快? 将25k C#转换为Java(2)

java转换为c#在上一篇文章中&#xff0c;我描述了如何将25k行C&#xff03;转换为Java以及从该练习中学到的教训。 我收到以下问题&#xff1a; 顺便说一句很棒的文章。 移植代码后&#xff0c;性能与C&#xff03;版本相比如何&#xff1f; 改写系统的动机之一是使系统运行更…

基于人工神经网络的识别C语言,实验一基于人工神经网络的数码识别.doc

实验一基于人工神经网络的数码识别《人工智能导论》课程基于人工神经网络的数码识别班级&#xff1a;计1103学号&#xff1a;201107010330姓名&#xff1a;贾梦洁成绩评定&#xff1a;评阅老师&#xff1a;日 期&#xff1a;实验报告正文一、实验目的?????基于神经网络的数…

博科光纤交换机java_带有光纤的可扩展,健壮和标准的Java Web服务

博科光纤交换机java这篇博客文章讨论了负载下的基准Web服务性能。 要了解有关Web服务性能理论的更多信息&#xff0c;请阅读利特尔定律&#xff0c;可伸缩性和容错 。 使用阻塞和异步IO对Web服务进行基准测试 Web应用程序&#xff08;或Web服务&#xff09;如何在负载下&#…

很棒的C语言入门笔记,推荐收藏!

点击蓝字关注我们c语言入门C语言一经出现就以其功能丰富、表达能力强、灵活方便、应用面广等特点迅速在全世界普及和推广。C语言不但执行效率高而且可移植性好&#xff0c;可以用来开发应用软件、驱动、操作系统等。C语言也是其它众多高级语言的鼻祖语言&#xff0c;所以说学习…

自定义日历控android,Android自定义日历Calender代码实现

产品要做签到功能&#xff0c;签到功能要基于一个日历来进行&#xff0c;所以就根据 要求自定义了一个日历自定义控件相信做android都知道&#xff1a;(1)首先创建一个类&#xff0c;继承一个容器类或者是一个控件(2)然后就是你需要设置的属性等的&#xff0c;在attrs文件夹中(…

java jsf_将Java 8日期时间API与JSF和Java EE 7结合使用

java jsf如果您将Java 8与Java EE 7一起使用&#xff0c;则在尝试利用某些Java 8新功能时可能会遇到一些怪癖。 一个这样的怪癖是&#xff0c;默认情况下&#xff0c;新的Date-Time API不适用于许多Java EE 7 API&#xff0c;因为它们是为与java.util.Date和/或更旧的Date API一…

C语言的注释要注意几点

点击蓝字关注我们如果领导给你一个项目的源码让你阅读&#xff0c;并理解重构代码&#xff0c;但里面一句注释都没有&#xff0c;我想这肯定是之前同事“删库跑路”了。看一份源码什么很重要&#xff1f;除了各种代码规范之外&#xff0c;还有一个比较重要的就是注释。注释虽然…

java自动推断类型_推断:Facebook的新Java静态分析工具

java自动推断类型如何使用Facebook的Infer改善Java开发工作流程&#xff1f; 如果您与技术话题保持同步&#xff08;如果您正在阅读此博客&#xff0c;我想您会这样做&#xff09;&#xff0c;那么您可能听说过Facebook 刚刚向公众发布的新工具&#xff1a;推断。 由于它来自F…

android官方架构组件,Android 架构组件官方文档01——LifeCycle

使用生命周期感知组件处理生命周期支持生命周期的组件执行操作以响应另一个组件(例如Activity和fragment)的生命周期状态更改。这些组件可帮助您生成组织性更好&#xff0c;并且通常更轻量的代码&#xff0c;这些代码更易于维护。常见的模式是在Activity和fragment的生命周期方…

C语言的核心和灵魂

点击蓝字关注我们提起C语言大部分开发者很自然就会想到指针二字&#xff0c;没错&#xff0c;作为C的核心和灵魂&#xff0c;它的地位咱们就不再赘述了。今天我们想跟大家讲的是指针中的两个特有名词&#xff1a;“悬空指针”和“野指针”。悬空指针C语言中的指针可以指向一块内…

gradle排除依赖_如何从Gradle中的所有依赖项中排除库

gradle排除依赖我正在使用Spring Boot。 默认情况下&#xff0c;Spring Boot带有Logback。 我想使用log4j&#xff08;出于任何原因..&#xff09; 为了做到这一点&#xff0c;我不得不排除logback并添加新的log4j依赖项&#xff1a; 在此软件包中“隐藏”了logback&#xff…

android搜索功能xml,Android_Android ActionBar搜索功能用法详解,本文实例讲述了Android ActionBar - phpStudy...

Android ActionBar搜索功能用法详解本文实例讲述了Android ActionBar搜索功能用法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;使用ActionBar SearchView时的注意点&#xff1a;首先要吐槽一下Android的官方Guide文档 &#xff0c;关于用法讲得不明确&#xff0c;可…

javaone_JavaOne 2015 –提交技巧和建议

javaone大家都知道JavaOne 。 感觉就像一直存在。 而且&#xff0c;即使我们跌宕起伏&#xff0c;而地理位置也不是我们想要的那样&#xff0c;旧金山也很昂贵&#xff0c;而且和。 这是有关各种Java的顶级会议。 今年又再次成为程序委员会&#xff08;“ Java&#xff0c;DevO…

C语言_结构体总结,附实例源码

点击蓝字关注我们当前文章介绍动态堆空间内存分配与释放&#xff0c;C语言结构体定义、初始化、赋值、结构体数组、结构体指针的相关知识点&#xff0c;最后通过一个学生管理系统综合练习结构体数组的使用。1. 动态内存管理C语言代码----->编译----->链接------>可执行…

android webview file,Android WebView 不支持 H5 input type=file 解决方法

最近因为赶项目进度&#xff0c;因此将本来要用原生控件实现的界面&#xff0c;自己做了H5并嵌入webview中。发现点击H5中 input type"file" 标签 不能打开android资源管理器。通过网络搜索发现是因为 android webview 由于考虑安全原因屏蔽了 input type"file&…

maven 常量字符串过长_从基于Maven的Web应用程序获取版本字符串

maven 常量字符串过长打包maven项目时&#xff0c;它将自动在其中生成pom.properties文件&#xff0c;其中将包含版本&#xff0c;artifactId和groupId信息。 这些在运行时很方便拥有并显示给您的Web应用程序。 可以使用如下方法检索它。 public class Application {private S…