最好使用私有方法还是受保护的方法?

36
在我的许多PHP项目中,我经常会使用非公共函数的类,这些函数我不打算扩展使用。
是将它们声明为protected还是private最好呢?
我可以看到双方的论点-将它们设置为private是更保守的方法,但也可以认为如果我想要扩展该方法并使基类扩展的方法清晰可见,则可以稍后将其设置为protected。
另一方面,私有是否会在某种程度上阻碍理论上未来的开发人员无需修改即可扩展我的代码?

2
好问题。这个问题也应该被标记为最佳实践。您可能希望删除PHP标签,因为它是一个很好的通用oop问题。 - Tom Moseley
我已经添加到最佳实践中,但我保留了PHP标签,因为我不确定术语是否总是相同的。 - Ciaran McNulty
2
请记住,private和protected在不同的编程语言中可能有略微不同的含义。因此,我认为PHP标签最好保留。 - troelskn
嗯,非常有趣的问题。我曾经强迫自己隐藏所有不需要暴露的东西。但是其他人会以意想不到的方式使用/扩展您的代码。如果它是要被继承的,那么保护它是正确的做法,这也是大多数好代码的做法。 - rvighne
10个回答

27

我的直觉是将它们保持私有,直到你需要它们变得不同为止。

有人声称(可惜我找不到链接了),将方法设为私有是不社交的,就像将它们设置为“final”一样,因为这种做法在相当程度上是独裁的,控制了人们如何使用你的代码。

然而,我并不认同这个观点,并且认为你应该仅暴露出你真正需要的内容。唯一的例外是库或工具包,在那里你期望用户以一般的方式扩展你的代码,而这是你无法预见的。在这种情况下,将选定的方法设为受保护的可以被看作提供弹性点。


12

我认为只有在必要时才暴露所需内容,这可以使修改的影响评估更容易。例如,如果一个方法是私有的,你就知道如果对其进行更改,影响将最小化。


6

个人而言,我认为应该尽可能保护隐私。我会审视每个方法并问自己是否希望派生类能够调用它。将所有内容设为protected会留下错误调用方法的可能性。

我想这归结于一个问题:“除非明确允许,否则一切都是禁止的”还是“除非明确禁止,否则一切都是允许的”。

另一个因素是,在未来的版本中将私有方法变为受保护的方法很容易。但是,一旦将方法设为受保护的,将其变为私有方法几乎是不可能的,因为您永远不知道自己会使哪些其他代码失效。


5
如果您打算构建一个可以继承的类,那么必须以这种方式进行设计,即将允许其他开发人员按照您预期的方式更改类行为的方法设置为受保护的。仅将所有方法设置为受保护的并不是一种非常好的设计。请记住,所有受保护的方法都成为公共API的一部分,因此如果您稍后更改了某些内容,则会破坏其他人的代码。
通常情况下,如果您不是为继承而设计,那么应该禁止其发生。

4

我通常避免使用private。我的理由是,如果你在两个类之间有继承关系,并且存在私有成员,那么这非常强烈地表明你应该将私有部分因子化为一个单独的对象。


3

私有关键字是有目的的。如果您不希望变量在继承类中混乱(或者您不希望人们在继承类中玩弄它们),那么为什么要考虑将它们设为受保护的呢?

不要让人们触碰您的私有部分 :)


9
"private" 这个关键字是有其特定用途的。这个说法并不十分有力。我相信 COBOL 也是有它的用途,但这并不代表我想要使用它。 - troelskn

1

我会将这些方法声明为私有的。这清楚地表明它们不是公共API的一部分。

不要担心未来可能发生的事情。


1
如果您实现的函数是特定于类的,并且不应在该类的上下文之外使用,则不要允许它被继承。例如,如果我们有一个动物层次结构,并且其中一种动物有一些仅对它们非常独特的东西,比如像海龟一样“在沙子里下蛋()”。这可能完全是海龟(乌龟等)所独有的,因此不应被任何其他动物继承。在这种情况下,我们会说它是私有的。另一方面,如果函数是“走路()”,那么它就不是唯一的,因此应该是可继承的。
起初似乎很模糊,因为大多数情况下应该继承,但也有更少见的情况,它们不应该被继承,因为它们是该类型所特有的。

1

如上所述,如果您稍后要扩展一个类,您总是可以随时更改它。

但是,如果您可以避免使用继承,那么应该这样做。在设计时最好使用其他模式,如果可能的话。

基本上要做的就是优先使用组合而不是继承,并编写接口而不是实现程序。

如果您让类只有一个紧密定义的目的,那么您可以组合对象而不是让它们相互继承。如果您使用接口而不是继承,则很可能会定义小而有效的接口。然后,您将看到继承将减少,因此对“受保护”的需求也将减少。

例如

interface sound {
 public function makeSound();
}

class bark implements sound{
 public function makeSound() {
   return "Bark!!!";  
 }
}

class meow implements sound{
 public function makeSound() {
   return "Meowmeow!!!";  
 }
}

class fourLeggedAnimal {
  private $sound;

  public function fourLeggedAnimal($sound){
    $this->sound = $sound;
  }
 
  public function eat(){
    echo $this->sound->makeSound();
  }

}

$cat = new fourLeggedAnimal(new meow());
$dog = new fourLeggedAnimal(new bark());

我知道这个示例远非完美。但它说明了技术,你可以以许多方式使用它。例如,你可以将其与不同的创建模式结合使用来构建猫和狗,可能不明智必须知道猫是会叫还是喵喵叫.. 但无论如何.. 这不同于必须制作一个基类,然后用猫和狗扩展它,因此必须将“声音”方法保护或覆盖公共吃方法。

/彼得


1

我通常只在某些非常特殊的情况下使用private关键字,其中方法/变量非常内部化,不应该被任何其他子类读取或写入(因此基本上几乎从不使用)。 我使用私有变量的唯一情况是例如:

final public function init():void
{
    if(!_initialized)
    {
        _init();
        _initialized = true;
    }

}

protected function _init():void
{
    // specific code.
}

在大多数情况下,方法和变量至少应该作为读取函数对继承有用。 因为当我使用别人编写的代码时,如果这个代码使用私有内容,通常会遇到很多麻烦: - 想要的行为未实现或不完整 - 无法使用私有方法 - 无法更改此方法,因为它是私有的 - 如果它是受保护的(或者如果我将其更改为受保护的),那么我就无法重构代码(例如在两个其他指令之间添加行为,因为此代码的一部分使用私有方法或变量...) = 最终你几乎需要将所有访问器更改为受保护的以获得扩展类的能力!
因此,如果您认为此类可以扩展,请优先选择保护除非特定情况(如果您认为特定方法只应使用但不应更改,请使用final protected)。
如果您认为此类在任何情况下都不应该被扩展:请使用私有。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接