无效方法为行为黑洞

如果“认为有害”的文章本身被认为是有害的,则本帖标题为“认为有害的作废方法”。 哦,好了

无效方法在大多数面向对象的代码库中无处不在。 在运行时中某个地方发生可变状态或I / O的直接后果是,您可以包装功能编程狂热者称为impure的任何行为,该行为原则上没有有意义的返回值。 一个常见的示例是在应用程序引导期间,例如在Java中:

@Resource MyClass implements Runnable {

// ...

@PostConstruct
public void init() {
    if(this.enabled) {
        this.executorService.scheduleAtFixedRate(
            this,
            0,
            500,
            TimeOut.MILLISECONDS);
    }
}

// ...
}

上面的代码据说不错,但是公共无效方法,尤其是它们在给定代码库中的扩散,显然是代码的味道。 即使以面向对象样式进行编码。

您的

公共方法供您的类合作者使用,它们是类功能的门户。 因此,它们应尽可能简洁,并提供实现类行为所需的最小表面积。 任何函数定义的一个主要的自记录部分自然就是其返回类型。

让我们从前面的示例开始:

@Resource MyClass implements Runnable {

// ...

@PostConstruct
public void init() {
    if(this.enabled) {
        this.executorService.scheduleAtFixedRate(
            this,
            0,
            500,
            TimeOut.MILLISECONDS);
    }
}

// ...
}

我们的类可能在构造时收到某种executorService实例,该实例可能是从某些依赖项注入粘合代码获得的,然后启动了工作计划。 客户代码需要显式调用init()的可能性通常很小。 这表明我们的@PostConstruct方法应该具有更严格的可见性,可能是privateprotected ,而这将是结束。

但是,真的吗?

可测性

假设我们要实际测试工作线程的关闭行为,这通常是一件棘手的事情。 您想做的事情大致如下:

// changed code from the original MyClass file:
@PostConstruct
public ScheduledFuture<T> init() {
    if(this.enabled) {
        return this.executorService.scheduleAtFixedRate(
            this,
            0,
            500,
            TimeOut.MILLISECONDS);
    }
}


public testExecutorShutdown(){
    ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
    MyClass c = new MyClass(service, true); // executorService, enabled
    ScheduledFuture<T> scheduled = c.init();
    executorService.shutdown();
    scheduled.get(1, TimeUnit.SECONDS); // throws exception
}

上面的测试代码测试了计划的操作在执行程序关闭后的1秒(或两次计划的迭代)内终止。 这样的测试依赖于访问由init方法返回的将来的对象。

自我记录

人类的知觉被他们当前的意识视野所遮盖

埃利亚·怀斯

我们对init()方法所做的更改启用了行为测试,但带来了一个重要的副作用: ScheduledFuture对象现在是MyClass公共接口的一部分,这意味着现在任何客户端代码都可以与其进行交互。 这是否是一个理想的属性,实际上取决于MyClass旨在支持的用例,并且可能您希望将ScheduledFuture封装在一个更友好的类中,例如,仅公开bool isDone()类的东西。

无论如何,保持上述init方法为空将始终导致您的客户端代码(或开发人员使用他/她的IDE浏览init签名)而无视MyClass.init()的实际作用。 只需看看不同的签名,然后想想自己针对每个签名进行编码:

public void init()
public ScheduledFuture<T> init()

后者将在您每次需要使用它时为您节省大脑周期,因为它可以清楚地说明其产生的效果,而无需查看代码或更深层次的文档。

一件事做好

当函数一次执行多个操作时,坚持函数返回一个值以明确声明其行为的想法显然是不可能的。 幸运的是,它本身就是一种代码味道 ,并且通过将返回类型视为函数的存在目的,可以使违反该原则变得更加奇怪。

结论

对您自己的未来以及对使用您的代码的所有开发人员都是好事,永远不要再在公共API中隐藏诸如返回值之类的宝贵信息。

拥抱与亲吻c。

翻译自: https://www.javacodegeeks.com/2018/05/void-methods-as-behavior-black-holes.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值