可选的monad和Java中的Demeter法则

当我查看一些代码时,我遇到了这个代码片段.

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方法中指定我不想返回地址.

最佳答案
好吧,你自己总结得很好:如果你想通过引入hasAddress()松散地结合,为什么要返回一个Optional.

Reading into what the LoD says,它谈到对“密切相关”的单位有“有限”的知识.听起来像是一个灰色的区域,但进一步说它还提到了“只有一个点”的规则.不过,我同意你的问题的评论,即空检查(或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类中.两者都有效,可读性/可维护性/清洁度取决于:

>具体案例
>此代码如何暴露给其他模块
> User类中需要的委托方法数
>您的架构(例如,如果您在UserDao类中,您是否真的想要将数据库访问移动到您的用户POJO类?难道DAO不是为了这个目的而制作的吗?这是否符合“密切相关”并且允许违反“只有一个点”规则?)
> ……

转载注明原文:可选的monad和Java中的Demeter法则 - 代码日志