私人与受保护 - 可见性良好实践关注

时间:2011-12-02 07:52:03

标签: oop language-agnostic coding-style

我一直在寻找,我知道理论上的差异。

  • 公开 - 任何类/函数都可以访问方法/属性。
  • protected - 只有此类和任何子类可以访问方法/属性。
  • private - 只有此类可以访问方法/属性。它甚至不会被继承。

这一切都很好,问题是,它们之间的实用区别是什么?您何时会使用private,何时使用protected?这个是否有标准或可接受的良好做法?

到目前为止,为了保留继承和多态的概念,我将public用于任何应该从外部访问的内容(如构造函数和主类功能),并使用protected作为内部方法(逻辑,辅助方法等)。我是在正确的轨道上吗?

(请注意,这个问题适合我,但也可供将来参考,因为我没有看到像这样的问题)。

6 个答案:

答案 0 :(得分:122)

不,你没有走上正轨。一个好的经验法则是:尽可能将所有内容都设为私有。这使您的类更加封装,并允许更改类的内部,而不会影响使用您的类的代码。

如果你设计你的类是可继承的,那么仔细选择可以从子类覆盖和访问的内容,并使其受到保护(最后,如果你想让它可访问但不能覆盖,那么谈论Java)。但请注意,只要您接受具有类的子类,并且存在受保护的字段或方法,此字段或方法就是该类的公共API的一部分,并且在不破坏子类的情况下可能不会在以后更改。

不应该继承的类应该是最终的(在Java中)。为了进行单元测试,您可以放松一些访问规则(私有到受保护,最终到非最终),然后记录它,并明确表示尽管该方法受到保护,但它不应该被覆盖。

答案 1 :(得分:42)

让我先说一下我在这里主要谈论方法访问,并在较小程度上标记类最终,成员访问。

古老的智慧

  

“将其标记为私人,除非您有充分理由不”

在开源管理开发人员库空间和VCS /依赖关系mgmt之前,

在写入的日子里有意义。由于Github,Maven等原因,它变成了超级协作。当时,通过限制图书馆的使用方式也可以赚钱。我职业生涯的前8或9年大概坚持这种“最佳实践”。

今天,我认为这是一个糟糕的建议。有时候有一个合理的论据来标记一个方法私有,或一个类最终,但它是非常罕见的,即使这样,它可能没有改进任何东西。

你有没有:

  • 感到失望,感到惊讶或受到图书馆等的伤害,这些图书馆有一个可以通过继承和几行代码修复的错误,但由于私有/最终方法和类被迫等待可能的官方补丁永远不会来?我有。
  • 想要使用一个库来处理与作者想象的略有不同的用例,但由于私有/最终方法和类而无法这样做?我有。
  • 对图书馆等感到失望,感到惊讶或受到伤害,因为它的可扩展性过于宽松?我没有。

这是我在默认情况下将方法标记为私有的三个最大的合理化:

合理化#1:它不安全,没有理由覆盖特定方法

我无法计算我是否有必要覆盖我所写的特定方法的错误次数。我曾经在几个流行的开源库中工作,我很难学会将事物标记为私有的真正成本。它通常会消除解决问题或用例的唯一实用解决方案。相反,我已经从未在16年以上的专业发展中,因为与API安全相关的原因而对保护而非私有的方法表示遗憾。当开发人员选择扩展一个类并覆盖一个方法时,他们会有意识地说“我知道我在做什么”。为了生产力,应该足够了。期。如果它是危险的,请注意它在类/方法Javadocs中,不要盲目地关上门。

默认保护的标记方法可以缓解现代软件开发中的一个主要问题:想象力的失败。

合理化#2:它保持公共API / Javadocs干净

这个更合理,并且取决于目标受众甚至可能是正确的事情,但是值得考虑保持API“干净”的成本实际上是:可扩展性。由于上面提到的原因,为了以防万一,标记受保护的内容可能更有意义。

合理化#3:我的软件是商业化的,我需要限制它的使用。

这也是合理的,但作为消费者,我每次都会选择限制较少的竞争对手(假设不存在明显的质量差异)。

永远不要说

我不是说永远不会将方法标记为私有。我说更好的经验法则是“除非有充分的理由不让方法受到保护”。

此建议最适合那些已经分解为模块的图书馆或大型项目的人员。对于较小或较多的单片项目,由于您无论如何都要控制所有代码,因此不太重要,如果需要,可以轻松更改代码的访问级别。尽管如此,我仍然会给出同样的建议: - )

答案 2 :(得分:16)

我刚才读了一篇文章,谈到尽可能地锁定每个班级。除非您有 立即 需要向外界公开某些数据或功能,否则请将所有内容设为最终版和私密版。在以后扩展范围总是很容易,但不是相反。首先考虑制作尽可能多的内容final,这样可以更轻松地在privateprotected之间进行选择。

  1. 除非您需要立即对它们进行子类化,否则请将所有类设为final。
  2. 将所有方法设为final,除非您需要立即进行子类化并覆盖它们。
  3. 将所有方法参数设为最终,除非您需要在方法体内更改它们,这在大多数时候都是有点尴尬。
  4. 现在,如果你留下最后一堂课,那么除非世界绝对需要一些东西,否则要把所有东西都当作私人 - 让它公之于众。

    如果你留下了一个确实有子类的类,那么仔细检查每个属性和方法。首先考虑是否要将该属性/方法公开给子类。如果你这样做,那么考虑一个子类是否会对你的对象造成严重破坏,如果它在覆盖过程中弄乱了属性值或方法实现。如果可能的话,你想要保护你的类的属性/方法,即使是从子类(听起来很讽刺,我知道),然后把它变成私有的。否则让它受到保护。

    免责声明:我在Java中编程不多:)

答案 3 :(得分:14)

停止滥用私人领域!!!

这里的评论似乎非常支持使用私人领域。那么,我有不同的想法。

原则上私人领域是否良好?是。但是当你不确定 肯定是错误的时,说黄金法则会使一切变得私密!在遇到问题之前,你不会看到问题。在我看来,如果您不确定,则应将字段标记为受保护。

您希望扩展一个类有两种情况:

  • 您想要为基类添加额外的功能
  • 您想要修改当前包之外的现有类(可能在某些库中)

第一种情况下私人领域没有任何问题。人们滥用私人字段这一事实会让你感到非常沮丧,因为你发现你无法修改狗屎。

考虑一个模拟汽车的简单库:

class Car {
    private screw;
    public assembleCar() {
       screw.install();
    };
    private putScrewsTogether() {
       ...
    };
}

图书馆作者认为:我的图书馆用户没有理由需要访问assembleCar()的实施细节吗?让我们把螺丝标记为私有。

嗯,作者错了。如果你只想修改assembleCar()方法而不将整个类复制到你的包中,那你就不走运了。您必须重写自己的screw字段。让我们说这辆车使用了十几个螺丝,每个螺丝都涉及一些不同的私人方法中的一些重要的初始化代码,这些螺丝都标记为私有。在这一点上,它开始吮吸。

是的,您可以和我争辩说,图书馆作者可以编写更好的代码,因此私有字段没有任何问题。我并不认为私有字段是 OOP 的问题。当人们使用它时,这是一个问题。

故事的寓意是,如果你正在写一个图书馆,你永远不知道你的用户是否想要访问一个特定的领域。如果您不确定,请将其标记为protected,以便以后每个人都会更开心。 至少不要滥用私​​人领域

我非常支持尼克的回答。

答案 4 :(得分:6)

您何时会使用private以及何时使用protected

可以将

隐私继承视为 根据 关系实施,而不是 IS-A 关系。简单地说,继承类的外部接口与继承类没有(可见)关系,它仅使用private继承来实现Base类提供的类似功能。

与Private Inheritance不同,受保护的继承是一种受限制的继承形式,其中派生类 IS-A 类型的Base类并且它希望将派生成员的访问权限仅限于派生类。

答案 5 :(得分:2)

如果付款类处理付款结算然后在产品类中为什么它需要整个计费过程,即支付方法如何支付在哪里支付,那么这就是封装的全部内容..所以只能让用于其他的东西对于那些其他类也会使用的类而言,类和对象只不过是那些公共类,对于那些仅限于扩展类的限制而言受到保护。因为你是madara uchiha私人就像"limboo"你可以看到它(你只上课一个班级)。