何时使用对象实例变量而不是将参数传递给方法

110

如何决定将参数传递给方法还是将它们声明为对象实例变量,这些变量对对象的所有方法都可见?

我更喜欢在类的最后将实例变量保存在列表中,但随着程序的增长,这个列表会变得越来越长。我想如果一个变量被经常传递,它应该只对需要它的所有方法可见,但是我也会想,“如果一切都是公开的,就根本不需要传递任何东西!”


1
如果您有具体的示例,您可能会得到更直接有用的答案。 - brabster
5个回答

62

鉴于您在提到实例变量,我假设您正在使用面向对象的编程语言。关于何时使用实例变量、如何定义它们的作用域以及何时使用局部变量在一定程度上是主观的,但在创建类时,可以遵循以下几个经验法则。

  • 通常认为实例变量是类的属性。 将其视为将从您的类创建的对象的形容词。如果您的实例数据可以用于描述对象,则很可能是实例数据的好选择。

  • 局部变量用于帮助方法完成其工作的范围内。 通常,方法应该具有获取某些数据、返回某些数据和/或处理/运行某些数据的算法等目的。有时,将局部变量视为帮助方法从头到尾完成过程的方式是有帮助的。

  • 实例变量范围不仅适用于安全性,也适用于封装性。 不要假设“目标应该是保持所有变量私有”。在继承的情况下,将变量设置为受保护的通常是一个不错的选择。与其将所有实例数据标记为公共的,不如为需要访问外部世界的那些数据创建getter/setter。不要使它们全部可用-只使用需要的那些。这将在开发生命周期中逐渐形成-很难一开始就猜到。

当涉及传递类中的数据时,如果没有看到代码,很难说您正在执行的操作是好的实践方法。有时,在实例数据上直接操作是可以的;其他时候则不行。在我看来,这是一种随着经验积累而发展直觉的技能。


1
我的答案是将此答案添加到H-Man2的答案(生命周期)中。如果它是对象的持久状态,则应该是成员属性。也就是说,该值在当前方法堆栈的范围之外本身就有意义。 - David Rodríguez - dribeas
1
我的直觉是同意David和H-Man2的观点。然而,我正在阅读Robert C Martin的《代码整洁之道》,在第3章中,他重构了代码,将某些东西从方法参数移动到成员变量中,因为有很多参数是不好的。总的来说,我想如果你的类只有一个职责,那么对象的生命周期与该计算的生命周期相同,所以也许实际答案是,如果你必须问这个问题,那么你的类太大了? - Andy
@DavidRodríguez-dribeas,您所说的方法堆栈是什么意思? - committedandroider
@committedandroider:如果该值超出当前函数调用的生命周期 - David Rodríguez - dribeas

53

主要取决于您存储在变量中的数据的生命周期。如果数据仅在计算期间使用,请将其作为参数传递。 如果数据绑定到对象的生命周期,请使用实例变量。

当您的变量列表太长时,也许考虑将类的某些部分重构为新类是一个不错的选择。


27

在我看来,实例变量只有当数据需要在函数之间传递时才是必要的。

以下是一个例子:

myCircle = myDrawing.drawCircle(center, radius);

现在让我们想象一下,myDrawing类使用了15个辅助函数来创建myCircle对象,并且每个函数都需要中心点和半径。但它们仍然不应该被设置为myDrawing类的实例变量,因为它们将永远不会再次需要。

另一方面,myCircle类需要将中心点和半径作为实例变量存储。

myCircle.move(newCenter);
myCircle.resize(newRadius);

为了让myCircle对象在进行新的调用时知道它的半径和中心是什么,它们需要被存储为实例变量,而不仅仅是传递给需要它们的函数。

因此,实例变量是保存对象“状态”的一种方式。如果一个变量不需要知道对象的状态,那么它就不应该是实例变量。

至于将所有内容都设为公共的,这可能会使你的生活变得更加轻松。但它将会回来折磨你。请不要这样做。


1
你可以只定义move函数使用参数(oldCenter, newCenter)。 - obesechicken13

4

个人认为:

如果变量是实例的状态的一部分,那么它应该是一个实例变量 - 类实例HAS-A实例变量。

如果我发现自己反复地将某些东西传递到实例的方法中,或者我发现我有大量的实例变量,我可能会尝试查看我的设计,以防我错过了什么或者在某个地方做出了错误的抽象。

希望对您有所帮助


3
当然,在类中保持一个公共变量的大列表很容易。但是,直观地说,您可以发现这不是正确的方法。
在使用变量之前定义每个变量。如果变量支持特定方法的功能,请仅在方法范围内使用它。
还要考虑安全性,公共类变量容易受到“外部”代码的非预期更改。您的主要目标应该是保持所有变量私有,并且任何不是私有的变量都应该有一个非常好的理由。
关于将参数传递到整个堆栈,这可能会很快变得混乱。一个经验法则是保持您的方法签名干净优雅。如果您看到许多方法使用相同的数据,请决定是否重要到足以成为类成员,如果不是,请重构您的代码以使其更有意义。
这归结为常识。确切地想想您何时以及为什么声明每个新变量,它的功能应该是什么,然后从那里做出关于其应该存在的范围的决定。

你经常希望方法是公共的,这样你就可以对它们进行单元测试。 - obesechicken13

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