5

我的问题与 Java 有关,但它也可以应用于 C#。我想知道为什么每个人都建议将实例变量设为private而不是将它们设为protected

让我们想一想。子类看不到私有变量,所以如果我需要访问或更改子类中超类的变量,我不得不使用一些访问器和修改器方法,例如getMyPrivateVariablesetMyPrivateVariable. 但是当您扩展某个类并继承其成员时,这就像您直接在子类中声明它们一样。所以从逻辑上讲,这意味着子类也应该可以直接访问实例变量,并为设计具有受保护变量的类提供了依据。我知道这种做法会破坏封装,但这在继承的情况下似乎无关紧要,因为在这种情况下,一切都像在子类中声明了超类的成员一样,所以子类具有“自然权利”能够直接访问其成员,无论它们是否被继承。在我看来,封装对于通过对象继承树之外的其他对象与对象进行交互更为重要。

所以,我的问题是为什么每个人都建议将类的实例变量声明为私有而不是受保护?

4

6 回答 6

1

你自己回答 - 封装。

例如,您有一个抽象的 Cat 类。这定义了成员变量 speed - 即它运行的速度。

抽象类还定义了一个最终的 run 方法,它显然会更新速度。

现在 - 如果 Cat 的子类 - 例如 Moggy 或 Tabby 可以直接访问和修改“速度”,那么它可能会破坏 run 方法。

所以最好把它绑在它开始的地方。如果需要,您也可以在本地声明它。

于 2013-06-30T18:56:27.970 回答
0

考虑以下“经验法则”:从班级外部可见的任何内容都将成为与外界签订的合同的一部分。为了让您自由地修改您的代码,而影响最小,您的目标是将可见性限制在尽可能低的范围内——人们通常不会限制他们的自由,除非他们被迫这样做。

换句话说,您必须有理由将成员声明为private. 一旦你有充分的理由,只将可见性提高到尽可能小的程度(首选应该是包私有/默认可见性)。那是因为您应该完全控制(或至少有一些控制)包中的代码,因此可以单独执行更改。作为旁注,“包私有”是唯一public可以应用于顶级类本身的可见性级别(除了 )。public因此,您应该考虑从不在其包外使用的类中删除修饰符。

可见性“protected逃脱”了您的控制范围,因为任何客户端都可能依赖于该特定变量或方法。

至于public,一个好的做法是只将它用于您实现的接口中声明的方法。

于 2013-06-30T20:23:25.917 回答
0

恕我直言,这是一个哲学问题。但我想这是在实例变量访问中添加安全层的问题。

通过 getter 和 setter 公开它们,您可以保证它们将被正确访问(例如,没有超出范围的值)关于您的类的角色。你也在为未来的干预做准备,通过隔离责任(例如,如果在某个时候你意识到应该系统地对特定变量进行一些处理,那么你只有一种方法可以改进,理论上不涉及其他任何东西,更重要的是不破坏整个程序的功能)。您还可以通过只提供一个 getter 方法来自由定义其中的一些只读。

所以基本上它增加了一层安全性,让你更好地控制你的变量。

此外,由于它们被称为实例变量,所以对我来说只有实际实例才能直接访问它们是有意义的。

于 2013-08-08T10:20:35.413 回答
0

如果您使您的实例变量受保护并且可以对您的类进行子类化(因为它不是final),那么每个人都可以对您的类进行子类化并在您不期望的时候更改您的实例变量。这极大地增加了您的功能无法按照您想要的方式运行的机会。您必须处理各种如何使用您的类,这使得您很难确保实例变量的每一次可能的更改都会在任何可能的更改时间点产生预期的结果。

于 2013-07-01T06:36:50.107 回答
0

OOP 的本质是发送消息,这意味着有利于数据行为

避免暴露变量的原因是使您的软件尽可能灵活。

客户不应该从任何地方获取一些数据并自行实现逻辑(逻辑不是他们责任的一部分),他们应该告诉!不要问!. 他们不应该掌握所需的算法,那应该是目标类的角色。

通过让您的变量protected在基类(或最终类..)中,您允许子类更改它们,而且很多时候,子类可能不知道也没有责任这样做。它通常会导致一些神秘的错误,例如从子类中为字段的基类分配一个意想不到的值。当然,protected在某些情况下需要,但仅当子类与相同的职责有关时。

因此,请始终尽可能限制您的变量/方法范围。因此,您的代码将是受保护的、灵活的、易于单元测试的(因为集中在一个地方),并且在向客户端公开实例变量时不会出现许多常见的错误。尤其是,您的班级可以在不破坏客户端代码的情况下更改其内部结构。

此外,当您不处理数据结构时,请避免使用 getter/setter。事实上,这将促进行为方法。

实际上,在 95% 的情况下,getter/setter 非常差(不要实现有价值的逻辑),并且只是使变量public/的最终运行protected

于 2013-08-08T10:30:09.997 回答
0

如果我需要访问或更改子类中的继承变量,我不得不使用一些访问器 [...]

你错了:private成员不是继承的。您可能将“继承”的含义与子类的实例拥有其超类的所有成员这一事实混淆了。

了解私有成员不被继承意味着什么的最好方法是观察子类可以声明自己的私有成员,这永远不会导致与超类的同名私有成员发生冲突。两人和平共处。

protected只有在设计一个专门用于子类化的类时才声明成员:在这种情况下,protected成员实际上是其公共 API 的一部分。大多数类不是为公共扩展而设计的,但声明它们final通常不是一种选择。如果这样的类有所有的成员protected,那将无异于创建它们,public因为任何客户端代码都可以轻松地创建它的虚拟子类,而不是向父类添加任何内容,而是暴露其内部。

于 2013-06-30T19:15:03.327 回答