如果我正在写一个课程,我何时将方法设为私有,而不是保护?换句话说,我怎么能预先知道客户端程序员从不需要覆盖方法?在某种情况下,它有外部因素,如数据库连接?
答案 0 :(得分:51)
public
和protected
方法构成对象的“接口”,public
用于使用(委托)您的类的开发人员,protected
用于希望< em>通过子类化来扩展对象的功能。
请注意,即使您的类将被子类化,也没有必要提供protected
方法。
public
和protected
接口都需要仔细考虑,特别是如果这是一个供您控制之外的开发人员使用的API,因为对接口的更改可能会破坏对现有方法做出假设的程序界面有效。
private
方法纯粹是为了对象的作者,可以随意重构,更改和删除。
默认情况下我会选择private
,如果你发现需要公开更多方法,请仔细考虑如何使用它们 - 特别是如果它们是虚拟的 - 如果它们被完全替换会发生什么有另一个开发人员的任意替代功能 - 你的班级仍然可以工作吗?然后设计一些适当的protected
,它们对于开发人员对您的对象进行子类化(如果需要),而不是暴露现有函数。
答案 1 :(得分:26)
换句话说,我怎么知道 推进客户程序员的意愿 永远不需要覆盖方法?
你做不到。你不需要。如果开发人员可能想要覆盖某个方法,更不用说如何,这不是你的工作。只是假设他想要并且无需触摸您的代码即可让他这样做。因此,如果您不需要,请不要声明方法private
。
如果开发人员觉得他需要调整课程的某些功能,他可以选择一些结构和行为模式,例如:装饰器,适配器或通过子类化。使用这些模式很好,因为它将更改封装到开发人员自己的类中,并保持自己的代码不变。通过声明方法private
,您可以确保开发人员会在您的课程中使用。这很糟糕。
一个完美的例子是Zend Framework的数据库适配器。他们不鼓励使用持久连接,并且它们的适配器没有为此提供任何手段。但是如果你想要这样做并且适配器方法被标记为private
(它不是,但是如果)会怎么样?由于无法覆盖该方法,您可以(是,您将)在其类中更改适配器代码,或者您将复制&amp;将代码粘贴到您自己的适配器类中,有效地复制99%的类只是为了更改单个函数调用。每当对此适配器进行更新时,您可能会丢失更改,或者您无法获得更改(如果您使用c&amp; p'd)。如果它被标记为protected
(,因为它是),您可以编写一个pConnectAdapter子类。
此外,在进行子类化时,您实际上是在说subClass 是 parentClass。因此,您可以期望派生类具有与parentClass相同的功能。如果parentClass中的功能在subClass中不可用,则在概念上禁用它属于subClass。
这就是为什么我发现更好的做法是将所有方法和属性默认为protected
可见性,并且只标记那些允许与我的类从另一个类或脚本进行交互的方法(不是属性){{{ 1}},但只有少数事情public
。这样,我给开发人员选择使用我的类,因为我打算使用它和调整它的选项。如果他在这个过程中打破了某些东西,那很可能是他的错,而不是我的。
更新:自从我四年前写这篇文章以来,我得出的结论是,将事务默认为保护而不是私有通常会导致次优的子类。这是因为人们会开始使用你提供的任何保护。这反过来意味着您必须将所有这些方法视为API,并且可能不会随意更改它们。因此,最好仔细考虑您想要提供的扩展点,并将其他所有内容保密。有关类似视图,请参阅http://fabien.potencier.org/article/47/pragmatism-over-theory-protected-vs-private。
答案 2 :(得分:9)
我通常会从最低级别开始。如果你不确定是否私密。然后根据需要,您可以保护或公开。
这个想法不是从私人到受保护的突破性改变,但从另一个方面来看可能是一个突破性的变化。
答案 3 :(得分:2)
不要将私有/受保护/公共事物视为程序员“需要”某种方法。可以把它想象成你想让它们访问它。
如果您认为应该允许他们更改数据库连接字符串,请将其公开。
答案 4 :(得分:2)
我总是将所有方法private
设为默认值。这是为了保持界面清洁和易于维护。
更改或隐藏已经可见的方法要比使私有方法更加明显更难。至少如果您需要与现有的客户端代码兼容。
答案 5 :(得分:0)
换句话说,我怎么知道 推进客户程序员的意愿 永远不需要覆盖方法?
如果你不知道他们需要。如果您没事(即,如果您认为他们应该可以),那么请使用protected
;否则使用private
。
答案 6 :(得分:0)
私有成员用于封装类的内部工作方式。使用它们来保存只有您希望能够访问的数据。例如,假设您有一个名为_name的字段和一个名为GetName()/ SetName(name)的getter / setter。在允许SetName成功之前,您可能希望对名称进行一些语法检查,否则会抛出异常。通过使_name为private,您可以确保在对名称进行任何更改之前进行此语法检查(除非您自己在自己的类中更改_name,在您自己的代码中)。通过让它受到保护,你对任何潜在的未来类的继承者说,“继续和我的领域一起蠢蠢欲动。”
一般而言,仅在特殊情况下才会谨慎使用受保护。例如,您可能有一个受保护的构造函数,它向子类公开了一些额外的构造功能。
答案 7 :(得分:0)
当我需要从基类调用它时,我通常会创建所有private
并重构。
除非我感到懒惰并且做一切protected
并不是绝对危险的。