私人或受保护的变量?

时间:2009-07-13 03:49:43

标签: oop

我目前正在阅读Code Complete,McConnell强烈建议将所有变量设为私有。 Coincedentally我恰好正在开展一个我需要更改私有变量的项目。

该类有一个私有变量(String)告诉它从哪里加载图像以在系统chrome中使用。我需要更改此图像,我不了解其他语言,但据我所知,在Flex / AIR中,无法覆盖私有变量。

如果它已被声明为受保护,我可以简单地扩展该类,并覆盖该变量。但由于它是私有的,我不得不从类中复制所有代码并创建一个重复的类,唯一的区别就是字符串。

我认为参数是使用私有,因为它使得超级和子类之间的松散耦合,但是我不得不完全违反DRY才能实现简单的字符串更改,这在我看来更糟糕。

这让我觉得受保护比私有更好。但是,我想以正确的最佳实践方式做事。因此,如果私有更好,我想了解原因。

如果普遍的共识是私人更好,有人可以解释为什么吗?

10 个答案:

答案 0 :(得分:26)

在这种情况下,该图像的位置曾经是基类的私有特定于实现的功能。您的新要求意味着它需要能够从一个派生类变为另一个派生类。

您应该将成员字段保持为私有,但要定义受保护的虚拟属性以将其公开给派生类:

private const string _defaultImagePath = @"C:\whatever.bmp";

protected virtual string ImagePath {
    get {return _defaultImagePath;}
}

在想要更改它的派生类中:

private const string _myImagePath = @"C:\other.bmp";
protected override string ImagePath {
    get {return _myImagePath;}
}

您还需要更改基类,以便在需要图像路径时使用该属性,而不是使用该字段。这是“封装场”重构。

答案 1 :(得分:4)

当您只知道定义它们的特定类将是唯一使用这些变量的类时,请创建变量private。但是,如果您要扩展课程,则应使用protected。私有实际上是因为你没有全局使用变量(所以你在类中使用getter和setter)这有助于放松耦合。扩展课程时,受保护是完全可以接受的。

一般来说,我会说使用最隐藏外部类和/或包中变量的访问类型。

答案 2 :(得分:2)

  

如果它被宣布为受保护,我   可以简单地扩展课程,   并覆盖了该变量。但   因为它是私人的,我不得不复制   来自类的所有代码并创建   只有一个重复的类   不同的是那个字符串。

如果图像位置有一个setter,你就根本不需要一个子类(或一个新类)。

如果不是想要更改图像,而是想要进行其他一些小改动,那么可能会使其他一些受保护/虚拟的API有所帮助。或许不是。我唯一的观点是,很难看到这样一个模糊的例子并从中获得一般智慧。

在类的行为和可扩展性方面为您提供多少灵活性,以及​​设计和测试类需要多少努力(以及如何理解,记录良好等方面的进一步交互)之间存在权衡取舍。班级是)。这些设计权衡无法在真空中进行评估,而必须在上下文中进行评估。类可能可能支持实际的各种功能/行为/扩展/更改的可能性有多大?精心设计的类是针对常见必要场景的扩展,缺少不必要的扩展和API。 (对于那里的扩展,可以选择简单的“setter”和更复杂的protected / virtual / subclassing扩展性......后者不是轻易选择的权衡。)

我不知道这会很好地回答你的具体问题(或者根本没有),但是当我读到你的问题的方式时,它让我觉得你暗示“最好让班级成为瑞士军刀因为可扩展性/可定制性很好“,我想说这些'好'的东西需要权衡。此外,你的问题似乎暗示这种情况是关于'私人'与'受保护'和'分类',而我认为一个简单的'setter方法'将是一个充分的API变化。

答案 3 :(得分:2)

当我第一次开始使用OO时,我曾经制作了所有内容publicprotected,并指出:“我为什么要限制其他人想用我的代码做什么?”

随着我获得更多经验,发生了两件事:

  1. 现代IDE出现了,制作它 非常容易改变 代码。
  2. 我必须保持很多 令人讨厌的代码已被扩展 它的设计者没有打算的方式。
  3. 现在我的方法是:将其设为private,直到您需要将其设为public(或protected) - 即使这样,也要认真思考这是否真的是正确的解决方案。

    一个好的protected方法是有意的扩展点,由设计者放在那里。我发现设计可扩展性实际上有点困难,你必须它 - 如果你只是把它打开并希望,你就要求维护噩梦了。 / p>

答案 4 :(得分:1)

“最佳实践”本身就是一个主观术语,虽然有许多约定用于改进一个人的代码,但每个约定的价值必须与您试图解决的问题的要求形成对比。

该变量声明为私有应该被视为变量开发意图的表达(即内部使用),这意味着您必须找到另一个可扩展点或重复代码。

从API设计的角度来看,应该使用private来隔离来自调用者的实现细节并保护它们以向继承者公开内容

答案 5 :(得分:1)

私人是,IMO,一开始总是最好的,然后在需要时公开/保护。创建新方法比尝试删除某人依赖的功能要容易得多。

在这种情况下,我认为最好的方法仍然是简单地包含一个二传手。您的子类是否必须提供任何其他功能,或者您是否刚刚创建了一个新实例,设置了路径并完成了它?

答案 6 :(得分:0)

作为课程实施的一部分,一切都必须是私人的,如果需要,你可以自由地改变它。

在您提到的示例中,可能没有完全定义类的接口,因为您需要更改类的私有属性。如果您可以控制代码,则可以保护属性,或者添加函数来获取和设置值。

答案 7 :(得分:0)

在需要保护之前将其设为私有。这是C#,C ++和Java等语言的抽象问题,其中protected / private与实现相关联。私人成员可以安全地自动内联,而受保护则不能。这类似于C#和C ++中的抽象问题,其中单态和多态需要虚拟关键字。

这实质上是一个脆弱的基类问题。将所有内容定义为受保护/虚拟在重用方面是最安全的,但会阻碍优化。将所有内容定义为私有/非虚拟是最有效的。

在像Eiffel这样的语言中,编译器会自动检测函数是否可以内联并自动检测某个特征是多态还是单态。 http://dev.eiffel.com

答案 8 :(得分:0)

受保护的成员是API的一部分,因为其他包中的派生类(即组织控制之外的包)可以看到它们。因此,他们代表了一种承诺。建议偏爱私人建议以避免做出不必要的承诺。你总是可以让一个不太明显的成员更加明显,但你不能总是这样做。

答案 9 :(得分:-1)

我可能是这里唯一同意我认为作者所暗示的内容的人。必须打开超类来对访问者进行更改的想法可能并不简单,并且可能并不总是一种选择。私有 - 直到它需要保护的方法是荒谬的,并最终意味着你没有真正有理由首先使用私人。

您希望将成员保持为私有的真正原因是,子类的实例无法对应保持锁定的超类实例的成员进行意外访问。不幸的副作用是缺乏可扩展性。 John Sanders的最高投票解决方案可能是最好的做法,因为它解决了这个问题。

但是,我已经设法编写了数千个类,经常使用受保护的(几乎没有私有的)变量,并且从来没有任何我称之为意外使用的问题。看起来同样可以通过简单地选择不以你正在弄乱其他类受保护值的方式来实现。

总而言之,我说:

  • 继续使用受保护的编码,但请记住,这会将敏感数据打开到子类。
  • 享受易于扩展的好处,但请记住在超类和子类之间保持“is-a”关系,以便每个类的行为都能与方法的内涵保持一致。
  • 如果您是硬核或需要额外保证,请使用私有变量/受保护的getter技术。