【问题标题】:Why did Java make package access default? [closed]为什么 Java 将包访问设为默认? [关闭]
【发布时间】:2013-12-18 07:48:41
【问题描述】:

我问这个问题是因为我相信他们这样做是有充分理由的,而且大多数人都没有正确使用它,无论如何,从我迄今为止的行业经验来看。但如果我的理论是正确的,那么我不确定他们为什么包含私有访问修饰符......?

我相信,如果正确使用默认访问,它可以在保持封装性的同时提供增强的可测试性。而且它还使私有访问修饰符变得多余。

默认访问修饰符可用于通过对需要对世界其他地方隐藏的方法使用唯一的包来提供相同的效果,并且它在不影响可测试性的情况下做到这一点,就像测试文件夹中的包一样,同样能够访问源文件夹中声明的所有默认方法。

我相信这就是 Java 使用包访问作为“默认”的原因。但我不确定为什么它们还包括私有访问,我确定有一个有效的用例......

【问题讨论】:

  • 当类具有其他类不得触及的内部方法时,私有是关键。我不确定这有什么争议。你是在暗示私人没有目的吗?!在这种情况下,我强烈反对
  • 在尝试轻松测试私有方法时出现问题,您可以通过创建另一个包来实现使用默认访问的私有成员的效果。
  • 是的,但是那些需要对一些密切相关的类而不是整个世界都可以访问的方法呢?此外,您似乎试图通过丢弃包访问来模拟私有。
  • 当然,您可以通过创建另一个包来包含该类来实现这一点,即使使用默认访问级别成员,也可以将其与世界隔离,因此包含私有方法和成员的类 X 将变为默认为 YX级别方法和成员。
  • 我的理解是 Y.X 是一个完全独立于 Y 的包(除了按照约定它们是相关的),包访问 Y.X 不能从 Y 访问,反之亦然

标签: java unit-testing encapsulation access-modifiers testability


【解决方案1】:

我建议进行一些思想实验。考虑这段代码:

public void promoteUser(User user)
{
    int newRank = computeNew(user);
    user.setRank(newRank);
}

private int computeNewRank(User user)
{
    return user.getRank() + 1;
}

有人可能会觉得应该测试computeNewRank(真正的实现可能会做更多的事情)。但是让我们暂时忘记这一点,并通过内联的魔力做到这一点:

public void promoteUser(User user)
{
    int newRank = user.getRank() + 1;
    user.setRank(newRank);
}

这个实验的美妙之处在于它适用于任何规模的私有方法。您总是可以想象自己内联私有成员并问自己“我真正想在这里测试什么?”。是私有方法本身还是伪装成私有方法的具有全新功能的新类/组件?关键是,您应该很少(如果有的话!)需要测试私有(甚至包/内部)成员。对于外部世界,对于您的合同消费者而言,这些都是无关紧要的细节。

现在,我们当然可以用系统测试代替一切。但是,您的常规工作流程会是什么样子?如果为了测试排名促销代码,您必须登录用户,注册会话,等待 3 分钟,输入促销代码,接收短信,确认......你明白我的意思了。

请记住,单元测试适合您,而不是相反。您可以弯曲、调整它们,使它们合身,这样您就可以交付质量更好的软件。他们的目的不是帮助您实现100% 覆盖率的神奇目标,而是为您提供有关您正在做什么的即时反馈,以便您可以更快地做出反应您将遇到的错误和故障。或者换句话说,提高您的工作效率

【讨论】:

  • 我理解维护合同的概念,但是如果合同被破坏,是否最好有效地隔离原因,更多的低级别测试会有所帮助。实现可能很大而且很复杂,理想情况下它们不应该如此,但通常它们是,至少默认访问将允许开发人员首先编写测试,这将更精确地突出显示错误,如果实现需要更改然后更改它并编写新的测试...
  • 这意味着这些实现可以被剖析,因此可以在任何级别更改实现。
  • 我认为私有对字段有用,但对方法没有用。
【解决方案2】:

我同意将默认(包私有)修饰符用于测试要访问的内容,但我不同意私有是不必要的。即使对于测试,也有很多不需要可见的东西。

对于一个好的测试,实现细节是不必要的,不应该在类外可见。测试的“白盒”越多,它就越脆弱。我通常将默认修饰符限制为我希望通过依赖注入设置并在测试中手动设置的字段。 (我也可以使用构造函数注入并摆脱它,但这更方便。)

【讨论】:

    猜你喜欢
    • 2017-01-24
    • 1970-01-01
    • 2015-04-09
    • 2020-07-01
    • 1970-01-01
    • 2011-10-08
    • 2017-08-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多