广州天与地网站建设,网站导航cms,网站制作 手机版,织梦网站模板如何安装教程视频svn: 没有演进历程信息引入了默认方法以启用接口演进。 如果向后兼容性是不可替代的#xff0c;则仅限于向接口添加新方法#xff08;这是它们在JDK中的唯一用法#xff09;。 但是#xff0c;如果希望客户端更新其代码#xff0c;则可以使用默认方法逐步演化接口而不会引… svn: 没有演进历程信息 引入了默认方法以启用接口演进。 如果向后兼容性是不可替代的则仅限于向接口添加新方法这是它们在JDK中的唯一用法。 但是如果希望客户端更新其代码则可以使用默认方法逐步演化接口而不会引起编译错误从而使客户端有时间将其代码更新为新版本的接口。 这个小型系列的第一部分说明了默认实现如何允许在不破坏客户端代码的情况下添加替换和删除方法。 我愚蠢地宣布“以后的文章将探讨替换整个接口的方法”同时也不会破坏客户端代码。 好吧您现在正在阅读这篇文章不幸的摘要是 我无法使其工作。 为什么 泛型。 到底为什么 你真的想知道吗 好吧那么请继续阅读但是这篇文章的其余部分实际上只是对我如何成为障碍的描述因此不要期望太多。 大激励是吗 总览 在描述我尝试过的方法和失败的方法之前我先定义要解决的问题。 问题陈述 这就是我们要做的 假定您的代码库包含一个接口您的客户端可以用所有可以想象的方式使用该接口它们具有自己的实现使用其实例调用您的代码并且您的代码返回此类实例当然他们将其用作参数的类型和返回值。 现在您要实质性地更改接口以无法用对单个方法的更改来表示的方式对其进行重命名移动或修改。 但是从提供一个版本到另一个版本的角度来看这两个接口仍然是等效的。 您可以执行此操作发布包含更改的新版本并告诉您的客户端修复其导致的编译错误。 如果他们的代码与您的代码高度耦合那么他们可能必须在单独的分支中执行此操作以花一些时间在代码上但这就是生活对吗 不过您真是个好人因此与其要求费时的一天不如让他们有机会随着时间的推移例如直到下一个版本逐渐更改其代码而没有任何编译错误。 请注意这是接下来所有内容的主要要求。我首先忽略了这是否是个好主意。我只是想看看自己能走多远。 我认为甚至有机会实现这一目标的唯一方法是定义一个过渡阶段在该阶段中新旧版本的接口都将共存。 因此我们真正需要的是一种通用的逐步方法该方法如何将实现调用者和声明从一个接口转移到另一个接口。 想法 在发布这篇文章时我对它的工作方式有一个具体的想法。 基本上与我在方法中使用的方法相同。 不断发展的接口方法 使用默认方法添加替换或删除接口的单个方法非常简单通常包括三个步骤在某些情况下更少 新版本库的新版本发布其中界面定义是过渡性的并结合了旧的和新的所需轮廓。 默认方法可确保所有外部实现和调用仍然有效并且在更新时不会出现编译错误。 过渡然后客户有时间从旧大纲过渡到新大纲。 同样默认方法可确保适应的外部实现和调用有效并且可以进行更改而不会产生编译错误。 新版本在新版本中该库删除了旧轮廓的残差。 鉴于客户端明智地利用了自己的时间并进行了必要的更改因此发布新版本不会导致编译错误。 如果您对这些步骤的详细说明感兴趣可以阅读我的早期文章 。 改进界面 对于这种情况这种方法似乎也很有意义所以我坐下来进行了探讨。 如果整个接口发生变化则要稍微复杂一点因为在方法仅具有调用者和实现的地方该接口也是一种类型即可以在声明中使用。 这使得必须区分三种使用接口的方式 内部使用 您在其中拥有实现和使用接口的代码 已发布的使用 您拥有实现但客户端调用了代码 外部使用 其中客户端拥有实现和使用接口的代码 起作用的部分采用与演化方法相同的方法 新版本使用新界面发布新版本以扩展旧版本。 让所有内部代码实现并使用新接口。 所有已发布的代码将使用旧接口声明参数类型并使用新接口返回类型。 如果必须转换实例则可以使用适配器来完成。 现在忽略参数化类型此更改将不会导致客户端代码中的编译错误。 过渡发布后客户端更改其代码。 从旧接口的实现已更改为实现新接口的实现和您已发布的代码返回的实例开始它们可以开始声明新类型的实例更新将它们传递给它们的方法的参数类型等等。上。 如有必要可以暂时使用适配器通过新接口与旧实例进行交互。 新版本发布一个删除旧界面的版本。 与不断发展的方法相同新接口中的默认实现允许客户端代码停止明确实现旧接口从而可以在第二个版本中将其删除。 此外旧接口上的便捷asNew()方法可以调用适配器以使其自身适应新接口。 我掩饰了一些细节但我希望你相信我这是可行的。 现在让我们回到泛型… 障碍 提出的方法中的关键部分是已发布的代码。 它由您的客户调用因此第一个发行版必须以兼容的方式对其进行更改。 并且由于所有内部代码都需要新接口因此它必须从Old到New 。 没有泛型它可能看起来像这样 在已发布的代码中将“旧”转换为“新” // in version 0
public Old doSomething(Old o) {// callToInternalCode requires an OldcallToInternalCode(o);return o;
}// in version 1 the method still accepts Old but returns New
public New doSomething(Old o) {// callToInternalCode now requires a NewNew n o.asNew();callToInternalCode(n);return n;
} 好的到目前为止很好。 现在让我们看看泛型的外观。 在已发布的代码中将“旧”转换为“新” –泛型 // in version 0
public ContainerOld doSomething(ContainerOld o) {// callToInternalCode requires a ContainerOldcallToInternalCode(o);return o;
}// in version 1
// doesnt work because it breaks assignments of the return value
public ContainerNew doSomething(ContainerOld o) {// callToInternalCode requires a ContainerNew// but we can not hand an adapted version to callToInternalCode// instead we must create a new containerNew nInstance o.get().asNew();ContainerNew n Container.of(nInstance);callToInternalCode(n);return n;
} 因此使用已发布的代码层从旧界面适应新界面通常不起作用原因至少有两个 由于Java中泛型的不变性返回值的所有分配都将中断 不变性打破分配 ContainerOld old // ...
// works in version 0; breaks in version 1
ContainerOld o published.doSomething(old); 不能将同一Container实例从已发布传递到内部代码。 这导致两个问题 创建一个新容器可能很困难或不可能。 该死的… 发布时间由交通运输的华盛顿州部门在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.htmlsvn: 没有演进历程信息