Streaming 的多项操作能否打破 Demeter 法则?
Can multiple operations with Streaming break The Law of Demeter?
我有点想用 Java 8 streaming 编写 Selenium 页面对象,如下面的代码所述,并得到评论说我的代码违反了 Demeter 法则,因为我在一条线。我被建议将代码分解为第一个流以收集到列表和 运行 另一个流操作来进行匹配(简而言之,根据需要将其分解为多个流)。我不相信,因为引入 Stream 来处理数据处理,如果我们将它分解为多个流,那么使用流就没有意义了。之前我曾在一个网络安全项目工作,其中数百万条记录通过流处理和多个逻辑操作来对数据进行排序。
请分享您的想法,我已按照审阅者的建议对其进行了更改,但他无法解释原因,我想了解有关流的更多信息以及利用 java 8 的这一强大补充的正确方法。
示例代码如下:
listOfWebElements.stream().filter(element -> element.getText().contains(name)).findFirst().ifPresent(match -> match.click());
是我在这个问题中所指的那一行,提供了方法以便它更有意义。
@FindBy(css = "#someTable td.some-name li a") List<WebElement> listOfWebElements;
public SomeClass doSomething(String name) {
wait.until(visibilityOfAllElements(listOfWebElements));
listOfWebElements.stream().filter(element -> element.getText().contains(name)).findFirst()
.ifPresent(match -> match.click());
return new SomeClass(driver);
}
Java 8 个流是 fluent interface, and are intended to allow writing in a functional programming style. There is a lot of disagreement over what breaks the LoD and whether it even matters, but all that aside, the example in the documentation for Stream
的示例,表明您正在按照 Java 语言设计者的意图使用它。
如果这对您的审阅者来说还不够,请注意 Demeter 法则(又名 最少知识原则)的目的是保持程序松散耦合最小化 class 直接与之通信的 classes 的数量。当 A
有一个 B
而 B
有一个 C
,并且你想让 A
让 C
做某事,你应该让它告诉B
完成它,让 B
担心如何以及何时使用 C
的细节。
在这种情况下,Stream
上的每个中间方法都返回 Stream
的另一个实例,因此您仍然只耦合到 Stream
class。我不会认为这是违反 Demeter 法则。
我还要说,一种语言中的任何 class 都应该被认为与该语言的标准库耦合。因此,任何标准库对象 都应该豁免 得墨忒耳法则,因为无论如何您都无法与它们分离。否则,您甚至无法在对象返回的 List
上调用 get
,或处理来自 [=27= 的 Map.Entry
的 Set
].当然,这也包括 Stream
。
I was suggested to break the code to first stream to collect to list and run another stream operation to do match( in short break it down into multiple streams as needed).
在局部变量中存储中间对象不会解决违反迪米特法则的问题,您仍然会访问其他对象返回的对象。听起来你的审稿人只是盲目 dot-counting.
Here是得墨忒耳法则的详解。当然有一些灰色地带,但实际上已经很明确了。
正如 Sean Van Gorder 的回答所指出的,使用 Streams 本身并不违反 LoD,链接方法调用也不违反。
然而最有可能违规的是这部分:
element.getText().contains(name);
根据 LoD,您不能 access/call 对您无法直接访问的任何内容使用方法。我假设 getText()
returns element
的一些内部状态。这不是您可以直接访问的内容,因此 contains(name)
方法调用是非法的。
我有点想用 Java 8 streaming 编写 Selenium 页面对象,如下面的代码所述,并得到评论说我的代码违反了 Demeter 法则,因为我在一条线。我被建议将代码分解为第一个流以收集到列表和 运行 另一个流操作来进行匹配(简而言之,根据需要将其分解为多个流)。我不相信,因为引入 Stream 来处理数据处理,如果我们将它分解为多个流,那么使用流就没有意义了。之前我曾在一个网络安全项目工作,其中数百万条记录通过流处理和多个逻辑操作来对数据进行排序。
请分享您的想法,我已按照审阅者的建议对其进行了更改,但他无法解释原因,我想了解有关流的更多信息以及利用 java 8 的这一强大补充的正确方法。
示例代码如下:
listOfWebElements.stream().filter(element -> element.getText().contains(name)).findFirst().ifPresent(match -> match.click());
是我在这个问题中所指的那一行,提供了方法以便它更有意义。
@FindBy(css = "#someTable td.some-name li a") List<WebElement> listOfWebElements;
public SomeClass doSomething(String name) {
wait.until(visibilityOfAllElements(listOfWebElements));
listOfWebElements.stream().filter(element -> element.getText().contains(name)).findFirst()
.ifPresent(match -> match.click());
return new SomeClass(driver);
}
Java 8 个流是 fluent interface, and are intended to allow writing in a functional programming style. There is a lot of disagreement over what breaks the LoD and whether it even matters, but all that aside, the example in the documentation for Stream
的示例,表明您正在按照 Java 语言设计者的意图使用它。
如果这对您的审阅者来说还不够,请注意 Demeter 法则(又名 最少知识原则)的目的是保持程序松散耦合最小化 class 直接与之通信的 classes 的数量。当 A
有一个 B
而 B
有一个 C
,并且你想让 A
让 C
做某事,你应该让它告诉B
完成它,让 B
担心如何以及何时使用 C
的细节。
在这种情况下,Stream
上的每个中间方法都返回 Stream
的另一个实例,因此您仍然只耦合到 Stream
class。我不会认为这是违反 Demeter 法则。
我还要说,一种语言中的任何 class 都应该被认为与该语言的标准库耦合。因此,任何标准库对象 都应该豁免 得墨忒耳法则,因为无论如何您都无法与它们分离。否则,您甚至无法在对象返回的 List
上调用 get
,或处理来自 [=27= 的 Map.Entry
的 Set
].当然,这也包括 Stream
。
I was suggested to break the code to first stream to collect to list and run another stream operation to do match( in short break it down into multiple streams as needed).
在局部变量中存储中间对象不会解决违反迪米特法则的问题,您仍然会访问其他对象返回的对象。听起来你的审稿人只是盲目 dot-counting.
Here是得墨忒耳法则的详解。当然有一些灰色地带,但实际上已经很明确了。
正如 Sean Van Gorder 的回答所指出的,使用 Streams 本身并不违反 LoD,链接方法调用也不违反。
然而最有可能违规的是这部分:
element.getText().contains(name);
根据 LoD,您不能 access/call 对您无法直接访问的任何内容使用方法。我假设 getText()
returns element
的一些内部状态。这不是您可以直接访问的内容,因此 contains(name)
方法调用是非法的。