私人与受保护能见度良好做法的关注

我一直在寻找,我知道理论上的区别。

  • Public -任何类/函数都可以访问方法/属性。
  • Protected -只有这个类和任何子类可以访问方法/属性。
  • Private -只有这个类可以访问方法/属性,它甚至不会被继承。

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

到目前为止,为了保留继承和多态性的概念,我使用 public来处理应该从外部访问的任何东西(比如构造函数和主类功能) ,使用 protected来处理内部方法(逻辑、辅助方法等)。我走对路了吗?

(请注意,这个问题是给我的,但也为未来的参考,因为我还没有看到这样一个问题,所以)。

139305 次浏览

不,你的方向不对。一个很好的经验法则是: 让一切尽可能私密。这使您的类更加封装,并且允许在不影响使用您的类的代码的情况下更改类的内部结构。

如果您将类设计为可继承的,那么请仔细选择可以从子类重写和可访问的内容,并将其设置为 protected (最后,谈到 Java,如果您希望使其可访问但不可重写)。但是请注意,一旦您接受了类的子类,并且有一个受保护的字段或方法,这个字段或方法就是类的公共 API 的一部分,以后可能不会在不破坏子类的情况下进行更改。

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

什么时候使用 private,什么时候使用 protected

私有继承 可以被认为是 按照 实施关系,而不是 IS-A 关系。简单地说,继承类的外部接口与继承类没有(可见的)关系,它只使用 private继承来实现基类提供的类似功能。

与私有继承不同,受保护的遗产是一种受限制的继承形式,其中派生类 IS-A 是 Base 类的一种,它希望将派生成员的访问限制在派生类中。

我前段时间读过一篇文章,讲的是尽可能多地锁定每一个类。除非 立即需要向外部世界公开某些数据或功能,否则一切都必须是最终的和私有的。将范围扩大到以后更容易,但反过来就不容易了。首先考虑使尽可能多的事情 final,这将使选择之间的 privateprotected容易得多。

  1. 使所有类成为最终类,除非你需要立即对它们进行子类化。
  2. 使所有方法都成为 final 方法,除非您需要立即对它们进行子类化和重写。
  3. 让所有的方法参数都是最终的,除非你需要在方法的主体中改变它们,这在大多数情况下是有点尴尬的。

现在,如果你还有最后一堂课要上,那么把所有的东西都变成私人的,除非这个世界绝对需要某些东西——把它变成公共的。

如果只剩下一个具有子类(es)的类,那么请仔细检查每个属性和方法。首先考虑是否要向子类公开该属性/方法。如果您这样做了,那么考虑一下,如果一个子类在重写过程中扰乱了属性值或方法实现,它是否会对您的对象造成严重破坏。如果可能的话,并且您希望从子类(我知道这听起来有点讽刺)中对类的属性/方法进行 保护,那么将其设置为私有的。否则就把它保护起来。

免责声明: 我不常用 Java 编程:)

如果 Paybill 类处理支付账单,那么在产品类中,为什么需要整个支付过程,即支付方式,如何支付,在哪里支付。.因此,只允许用于其他类和对象的内容仅限于那些其他类也将使用的公共内容,保护仅用于扩展类的内容。因为你是马达拉 uchiha 的私人是喜欢 "limboo"你可以看到它(你类只有单一类)。

首先我要说的是,我在这里主要讨论的是方法访问,在一个稍小的范围内,标记类 final,没有成员访问。

古老的智慧

“标记为隐私,除非你有充分的理由不这样做”

在开源占据开发人员库空间和 VCS/依赖项 mgmt 之前,它在编写的时候就有意义了。由于 Github,Maven 等等,变得超级协作。当时还有通过限制图书馆的使用方式来赚钱的方法。在我职业生涯的头8到9年里,我严格遵守了这个“最佳实践”。

今天,我认为这是个糟糕的建议。有时候会有一个合理的参数来标记方法 private 或者类 final,但是这种情况非常罕见,即使这样也可能不会改进任何东西。

你有没有过:

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

这是我听到的默认标记私有方法的三个最大的合理化解释:

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

关于是否有必要重写我所写的特定方法,我已经数不清自己错了多少次了。在开发了几个流行的开源库之后,我艰难地了解了标记私有内容的真正成本。它常常排除了对不可预见的问题或用例的唯一实际解决方案。相反,我在16年以上的专业发展经验中发现,由于与 API 安全相关的原因,我对标记受保护的方法而不是私有的方法感到遗憾。当开发人员选择扩展类并重写方法时,他们是在有意识地说“我知道自己在做什么”为了提高生产力,这应该足够了。句号。如果它是危险的,请在类/方法 Javadocs 中注意,不要盲目地关闭它。

缺省保护的标记方法缓解了现代 SW 开发中的一个主要问题: 想象力的失败。

合理化 # 2: 它保持公共 API/Javadocs 的整洁

这一条更合理,而且根据目标受众的不同,它甚至可能是正确的做法,但是值得考虑的是保持 API“干净”的代价实际上是什么: 可扩展性。出于上面提到的原因,为了以防万一,标记默认受保护的内容可能更有意义。

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

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

永不言败

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

这个建议最适合那些从事图书馆工作或者大型项目的人,因为这些项目已经被分解成了模块。对于较小的或更多的单体项目来说,这并不那么重要,因为你无论如何都可以控制所有的代码,而且如果你需要的话,很容易改变你的代码的访问级别。尽管如此,我还是会给出同样的建议: -)

停止滥用私人领域! ! !

这里的评论似乎是压倒性的支持使用私有字段。好吧,那么我有一些不同的东西要说。

私人领域原则上是好的吗?是的。但是说 一条金科玉律就是在你不确定的时候把所有事情都保密 绝对是错的!直到你遇到问题,你才会发现问题。在我看来,如果不确定,应该将字段标记为 protected

有两种情况需要扩展类:

  • 您希望向基类添加额外的功能
  • 您希望修改位于当前包之外的现有类(可能在某些库中)

在第一种情况下,私人领域没有什么问题。事实上,人们滥用 二等兵字段使它如此令人沮丧,当你发现你不能修改狗屎。

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

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

图书馆作者想: 没有理由我的图书馆的用户需要访问 assembleCar()的实现细节对吧?让我们把螺丝钉标记为隐私。

作者错了。如果您只想修改 assembleCar()方法而不想将整个类复制到您的包中,那么您就不走运了。您必须重写自己的 screw字段。假设这辆车使用了十几个螺丝每个螺丝都涉及到不同私有方法中的一些重要的初始化代码这些螺丝都被标记为私有。这时候,就开始糟糕了。

是的,你可以和我争论 库作者可以编写更好的代码,所以私有字段没有什么问题。我并不是说 二等兵字段是 的问题。当人们使用它们时,这是一个问题。

这个故事的寓意是,如果你正在编写一个库,你永远不知道你的用户是否想要访问一个特定的字段。如果你不确定,标记为 protected,这样以后每个人都会更高兴。至少不要滥用私人领域.

我非常支持尼克的回答。