在我查看一些代码时,我遇到了这个代码段。
List<User> users = /* Some code that initializes the list */;
users.stream()
.filter(user -> user.getAddress().isPresent())
.map(/* Some code */)
// And so on...
方法user.getAddress()
的调用会返回Optional<Address>
。遵循着名的德米特法则(LoD),上面的代码并不干净。但是,我无法弄清楚如何重构它以使其更清洁。
首次尝试可能是向User
类添加方法hasAddress()
,但此方法无需使用Optional<Address>
,IMO。
我应该如何重构上述代码?在这种情况下,是否值得满足LoD?
编辑:我错过了在map
方法中指定我不想返回地址。
答案 0 :(得分:3)
嗯,你自己总结得很好:如果你想通过介绍hasAddress()
来松散地结合,为什么要返回Optional
。
Reading into what the LoD says,它谈论的是&#34;限制&#34;关于&#34;密切相关的知识&#34;单位。听起来像是一个灰色区域,但进一步说它还提到了#34;只有一个点&#34;规则。尽管如此,我同意你的问题的评论,即空检查(或isPresent()
)完全没问题(哎,真正的空检查在技术上甚至不需要点; P)。
如果您想真正封装更多内容,可以完全删除getAddress()
,而是提供:
class User {
private Optional<Address> address;
boolean hasAddress() {
return address.isPresent();
}
// still exposes address to the consumer, guard your properties
void ifAddressPresent(Consumer<Address> then) {
address.ifPresent(then::accept);
}
// does not expose address, but caller has no info about it
void ifAddressPresent(Runnable then) {
address.ifPresent(address -> then.run());
}
// really keep everything to yourself, allowing no outside interference
void ifAddressPresentDoSomeSpecificAction() {
address.ifPresent(address -> {
// do this
// do that
});
}
}
但是,正如评论者指出的那样:是否值得/必要?所有这些法律/原则都不是绝对的,而是比教条更具指导性。在这种情况下,它可能是关于平衡LoD与KISS。
最后,您需要决定此特定示例是否会从将流的功能移动到User类中获益。两者都有效,可读性/可维护性/清洁度取决于:
答案 1 :(得分:1)
不知道它是否更干净(因为你需要使用getAddress
返回一个可选的事实),但在Java 9中你可以这样做:
users.stream()
.map(User::getAddress)
.flatMap(Optional::stream)
.map(/* Some code */)
或
users.stream()
.flatMap(user -> user.getAddress().stream())
.map(/* Some code */)
答案 2 :(得分:0)
我相信你已经自己回答了这个问题。
这里有两个不同的用例:
第一个用例可以通过添加方法<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.hacker.timernotification">
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Repeating_activity"/>
<receiver android:name=".Notification_receiver"
android:directBootAware="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
来解决,就像你说的那样。
可以使用{{1}}来解决第二个用例来包装地址。这没什么不对。
答案 3 :(得分:0)
LoD要求您考虑的是地址的价值是否需要给出(即,请求/访问)。如果答案是肯定的 - 那么你需要处理空值或空值的情况;否则,您可以考虑是否可以请求存在地址。
因此,如果它对于要发出的地址有效,则返回Optional处理空值的情况,并可用于确定是否存在。检查可选的空虚&#39;在我看来,与检查0的整数是一样的 - 你没有访问某个其他对象的属性,只是你给出的对象的属性。
如果只允许知道存在,则isPresent方法可能更好。当然,如果您正在处理SQL值,那么可能需要一个Optional来处理SQL NULL值。
否则,为什么这个过滤发生在这里?
答案 4 :(得分:0)
另一种方法是将计算移动到用户类。
由于用户有地址,他应该能够回答有关地址的问题而不必暴露它。那样你就满足了LoD