方法链接的优缺点,以及用对象本身替换所有 void 返回参数的可能性

2022-09-01 19:48:34

我最感兴趣的是Java,但我认为这是一个普遍的问题。最近我一直在使用Arquillian框架(),它使用了很多方法链。方法链接的其他示例是 , 中的方法。使用这种方法有明显的好处:减少冗长是其中之一。ShrinkWrapStringBuilderStringBuffer

现在我想知道,为什么不是所有具有返回参数的方法都实现为可链接的?链接中肯定有一些明显和客观的缺点。因为如果所有方法都是可链接的,我仍然可以选择不使用它。void

我不是要求更改Java中的现有代码,这可能会在某个地方破坏某些内容,但是解释为什么没有使用它也会很好。我更多的是从未来的框架(用Java编写的)设计角度来询问的。


我发现了一个类似的问题,但最初的提问者实际上想知道为什么它被认为是一种好的做法:方法链 - 为什么它是一种好的做法,或者不是?


虽然有一些可用的答案,但我仍然不确定链接的所有优点和缺点是什么,以及让所有void方法都可链接是否有用。


答案 1

缺点

  • 原则上,它混淆了签名,如果某些东西返回一个新实例,我不希望它也是一个突变体方法。例如,如果一个向量有一个 scale 方法,那么如果它有一个返回值,我会假设它返回一个由输入缩放的新向量,如果它没有,那么我希望它在内部缩放。
  • 当然,如果类被扩展,你会遇到问题,在链接的中途,你的对象被强制转换为超类型。当链接方法在父类中声明,但在子类的实例上使用时,会发生这种情况。

好处

  • 它允许将数学方程式样式的代码编写为完整的方程,而无需多个中间对象(导致不必要的开销),例如,如果没有方法链接,向量三重交叉积(作为随机示例)必须编写为

    MyVector3d tripleCrossProduct=(vector1.multiply(vector2)).multiply(vector3);
    

    其缺点是创建必须创建和垃圾回收的中间对象,或者

    MyVector3d tripleCrossProduct=vector1;
    tripleCrossProduct.multiplyLocal(vec2);
    tripleCrossProduct.multiplyLocal(vec3);
    

    这避免了中间对象的创建,非常不清楚,变量名称实际上是一个谎言,直到第3行。但是,如果您有方法链接,则可以以正常的数学方式简明扼要地编写,而无需创建不必要的中间对象。tripleCrossProduct

    MyVector3d tripleCrossProduct=vector1.multiplyLocal(vector2).multiplyLocal(vector3);
    

    所有这些都假设vector1是牺牲性的,永远不需要再次使用。

  • 当然还有明显的好处;简洁。即使您的操作在我上面示例的庄园中没有链接,您仍然可以避免对对象进行不必要的引用

    SomeObject someObject=new SomeObject();
    someObject
      .someOperation()
      .someOtherOperation();
    

NB不是用作Java的真实类,而是假设在调用方法时执行交叉积。 不是为了让那些不熟悉向量演算的人更清楚地使用“意图”
NB Amit的解决方案是使用多行方法链接的第一个答案,我将其作为完整性的第四个项目符号的一部分MyVector3d.multiply().cross()


答案 2

方法链接是实现流畅接口的一种方法,与编程语言无关。它的主要优点(可读代码)可以确切地告诉您何时使用它。如果没有特别需要可读的代码,最好避免使用它,除非API自然地设计为返回上下文/对象作为方法调用的结果。

步骤 1:流畅的接口与命令查询 API

必须针对命令查询 API 考虑 Fluent 接口。为了更好地理解它,让我在下面编写命令查询 API 的项目符号列表定义。简而言之,这只是一种标准的面向对象编码方法:

  • 修改数据的方法称为 。命令不返回值。Command
  • 返回值的方法称为 .查询不会修改数据。Query

遵循命令查询 API 将为您提供以下好处:

  • 查看面向对象的代码,您就会了解正在发生的事情。
  • 代码的调试更容易,因为每个调用都是单独发生的。

步骤 2:基于命令查询 API 的 Fluent 界面

但是命令查询API由于某种原因而存在,而且它确实读起来更好。那么,我们如何同时获得流畅的界面和命令查询 API 的优势呢?

答:流利接口必须在命令查询 API 之上实现(而不是流利接口替换命令查询 API)。将流利的接口视为命令查询 API 的外表。毕竟,它被称为流畅的“接口” - 一个基于标准(命令查询)API的可读方便的接口

通常,在命令查询API准备就绪(编写,可能是单元测试,抛光以轻松调试)之后,您可以在其上编写一个流畅的界面软件层。换句话说,Fluent 接口通过利用命令查询 API 来完成其功能。然后,在需要方便和可读性的任何位置使用流畅的界面(带有方法链接)。但是,一旦你想了解实际发生的事情(例如,在调试异常时),你可以随时深入研究命令查询API - 很好的旧的面向对象代码。


推荐