默认访问权限不会使私有访问修饰符变得多余。
语言设计师对此的立场反映在官方教程《控制对类成员的访问》中,这一点很清楚(为方便起见,引号中的相关陈述用粗体表示):
选择访问级别的提示:
如果其他程序员使用您的类,则要确保不会发生由于滥用而引起的错误。访问级别可以帮助您做到这一点。
- 使用对特定成员有意义的最严格的访问级别。除非有充分的理由,否则请使用private。
- 避免使用除常量之外的公共字段。(本教程中的许多示例都使用公共字段。这可能有助于简洁地说明一些要点,但不建议在生产代码中使用。)公共字段倾向于将您链接到特定的实现,并限制了更改代码的灵活性。
您呼吁可测试性作为完全放弃私有修饰符的理由是错误的,例如,“ TDD新手”中的答案就证明了这一点。我现在应该避免使用私有方法吗?
当然,您可以使用私有方法,也可以测试它们。
有某种方法可以使私有方法运行,在这种情况下,您可以用这种方法进行测试,或者没有办法使私有方法运行,在这种情况下:为什么您要尝试对其进行测试,只是删除该死的东西...
在另一个官方教程“ 创建和使用软件包”中解释了语言设计人员在软件包级别访问的目的和用途上的立场,它与删除私有修饰符的想法没有共同之处(为方便起见,引号中的相关陈述用粗体表示) :
出于以下几个原因,应将这些类和接口捆绑在包中:
- 您和其他程序员可以轻松确定这些类型是否相关...
- 您可以允许包内的类型彼此不受限制地访问,但仍然限制包外的类型的访问 ...
<rant“我想我已经听到了足够的抱怨声。猜测是时候该大声说清楚了……“>
私有方法有益于单元测试。
下面的注释假定您熟悉代码覆盖率。如果没有,花点时间学习,因为它对那些对单元测试和所有测试感兴趣的人非常有用。
好吧,所以我有了私有方法和单元测试,覆盖率分析告诉我还有差距,我的私有方法没有包含在测试中。现在...
从私有化中我会得到什么
由于method是私有的,因此唯一的方法是研究代码以了解如何通过非私有API使用它。通常,此类研究表明存在差距的原因是测试中缺少特定的使用场景。
void nonPrivateMethod(boolean condition) {
if (condition) {
privateMethod();
}
// other code...
}
// unit tests don't invoke nonPrivateMethod(true)
// => privateMethod isn't covered.
为了完整起见,造成这种覆盖差距的其他(较不频繁)原因可能是规范/设计中的错误。为了简单起见,我不会在这里深入研究这些内容。足以说,如果您弱化访问限制“只是为了使方法可测试”,您将错过机会了解这些错误的存在。
很好,为了弥补差距,我为缺失的场景添加了单元测试,重复进行覆盖率分析并验证差距是否消失。我现在有什么?我已经获得了针对非专用API的特定用法的新单元测试。
新测试可确保此用法的预期行为不会在没有通知的情况下发生更改,因为如果更改,则测试将失败。
外部读者可以研究该测试并了解其使用方式和行为方式(此处,外部读者包括我将来的自我,因为在完成测试后一个月或两个月,我往往会忘记代码)。
新测试可以重构(我可以重构私有方法吗?您敢打赌!)无论我做什么privateMethod
,我都会一直想测试nonPrivateMethod(true)
。不管我做什么privateMethod
,都不需要修改测试,因为方法不是直接调用的。
不错?你打赌
我应该从弱化访问限制中放松些什么
现在想象一下,而不是上面的内容,我只是削弱了访问限制。我跳过了对使用该方法的代码的研究,直接进行了调用my的测试exPrivateMethod
。大?不!
是否可以针对上述非私有API的特定用法进行测试?否:以前没有测试,nonPrivateMethod(true)
现在没有这种测试。
外部读者是否有机会更好地了解课堂使用情况?否。“-嘿,这里测试的方法的目的是什么?-算了,它仅供内部使用。-糟糕。”
可以容忍重构吗?没办法:无论我进行什么更改exPrivateMethod
,都可能会破坏测试。重命名,合并到其他方法中,更改参数并测试将停止编译。头痛?你打赌!
总结起来,坚持使用私有方法可以为我带来有用,可靠的单元测试增强。相比之下,弱化“可测试性”的访问限制只会给我带来晦涩难懂的测试代码,此外,它还存在被任何较小的重构破坏的永久风险。坦白地说,我得到的东西看起来像技术性债务。
</ rant>