【问题标题】:VBA difference between public variable and property公共变量和属性之间的VBA区别
【发布时间】:2014-08-22 00:19:14
【问题描述】:

有什么区别

Public Variable As Integer

Private pVariable As Integer

Public Property Let Variable(ByVal lVariable As Integer)
    pVariable = lVariable
End Property

Public Property Get Variable()
    Variable = pVariable
End Property

在 VBA 类模块中?

我为什么要使用第二个版本?

【问题讨论】:

  • 第二个方法(属性)允许外部访问,就好像该字段是公共的一样,同时允许类过滤数据。对于 Let 属性,它可能会检查有效性,例如不接受负数。对于 Get 属性,它可能会计算一个在类中实际上并不存在的“变量”,例如mass Get 属性 可能会返回密度乘以体积的乘积。您还可以通过省略 Let 或 Get 属性将属性设为只读(或只写 -- 不常用)。

标签: vba class oop properties interface


【解决方案1】:

尽管 VBA 是面向对象的,但它在许多方面仍然受到限制,但就本示例而言,仅了解 VBA 中 OOP 的基础知识就足够了。

您的代码

Private pVariable As Integer

Public Property Let Variable(ByVal lVariable As Integer)
    pVariable = lVariable
End Property

Public Property Get Variable()
    Variable = pVariable
End Property

有点没必要

注意:如果您想处理错误/验证传入的数据,您可以这样做,但通常如果它像设置和获取值一样简单,您就不会这样做。 p>

如果您同时公开 Let/Set 和 Get 属性,为什么还需要私有支持字段?为此,您只需要公共变量本身,不需要属性。

当您只需要公开其中一个属性而不公开其他属性(即,仅 setter 或 getter)时,故事会发生 360 度变化。也许通过一个例子更容易理解......

示例

让我们从一个简单的“银行”示例开始(显然你不会在现实生活中的 VBA 中这样做,但作为基础进行评估是一个很好的概念

假设您必须构建一个类来模拟银行帐户。您需要一种从帐户中获取depositwithdraw 资金以及显示balance 的方法。

通常,您不会balance 字段设置setter,因为不应允许任何人明确地set 余额。 (如果您知道允许这样做的银行,请告诉我;))。实际余额应该是一个私有变量。应该有一个属性可以公开它,这就是您应该在这里考虑的全部内容。

考虑一个 VBA 类(一个接口)

IAccountServices.cls

Sub Deposit(amount As Double)
End Sub

Sub WithDraw(amount As Double)
End Sub

和另一个代表帐户的类

Account.cls

Implements IAccountServices

' balance should be private
' cause you should only have a getter for it
' you should only be able to set the balance inside this class
' based on the operations
Private accBalance As Double

' see Getter only - no setter
Public Property Get Balance() As Double
    Balance = accBalance
End Property

Public Function Deposit(amount As Double)
    accBalance = accBalance + amount
End Function

Public Function WithDraw(amount As Double)
    accBalance = accBalance - amount
End Function

Private Sub IAccountServices_Deposit(amount As Double)
    accBalance = accBalance + amount
End Sub

Private Sub IAccountServices_WithDraw(amount As Double)
    accBalance = accBalance - amount
End Sub

注意:这显然是最简单的示例,它没有任何错误处理或检查余额是否足以提取等。这仅用于演示目的,不用于实际-生活应用。

有了这个封装,我马上就看到/知道了

  • accBalance 是一个在课堂之外的任何地方都无法访问的私有字段

  • 我只能检索 balance() 而不能在 Account 类的实例上显式设置它。

  • 我可以deposit()withdraw()从账户中取钱(公开方式)


在您的标准模块 (module1) 中,即使使用智能感知,您也会列出 .Balance,这就是您的库/类用户所需要担心的全部内容。

现在有一个标准编码模块来测试这两个类 (Module1)

Sub Main()

    Dim myAccount As Account
    Set myAccount = New Account

    Debug.Print "Starting Balance: " & myAccount.Balance

    myAccount.Deposit (2000)
    Debug.Print "Deposited: 2000"

    myAccount.WithDraw (250)
    Debug.Print "Withdrew: 250"

    Debug.Print "Ending Balance: " & myAccount.Balance

    ' can't set balance
    ' myAccount.Balance = 999999999999999999999999
End Sub

要了解 VBA OOP,我可以推荐:

【讨论】:

  • 您可能仍希望使用 LetGet 进行封装以执行错误检查等。除非您出于严格的性能原因这样做(在这种情况下,您最好制作一个 DLL使用 C++ 然后引用它)更好的做法是保留稍后通过错误检查或条件响应来增强或改进类功能的选项。但是非常详细的解释,所以+1。
  • 正如 hnk 所指出的,仍然有正当理由使用 LetGet 只是为了允许对其他私有变量进行错误检查。所以我不会说 OPs 代码是错误,只是有点不必要/非最佳。尽管我的学术背景是 C++/C#,但对我来说,使用带有 get 和 let 的私有变量似乎是一种好习惯。
  • 感谢@Aiken & hnk 用您的有效观察更新了答案。
  • 属性不限于类模块。它们也可以在标准代码模块中使用!
【解决方案2】:

属性允许外部访问,就好像该属性是公共字段一样,同时允许类保持对数据的控制。

Get 属性可能会计算出类中实际不存在的“变量”。例如。 mass Get 属性可能会返回密度乘以体积的乘积。

Private density as Double
Private volume as Double
Private potentialEnergy

Public Property Get mass() As Double
   mass = density*volume
End Property 'Property Get mass

Let 属性可能会检查有效性,例如不接受负数。或者它可以保持对象的字段属性同步:

Public Property Let density(rho as Double)
   if rho > 0 then
      density = rho
      potentialEnergy = density * volume * gravity * height
End Property 'Property Get mass

您还可以通过省略 Let 或 Get 属性将属性设为只读(或只写 -- 不常用)。

除了性能略有下降之外,最好从一开始就为您允许公共访问的任何字段使用属性,即使这些属性最初是微不足道的,以方便将来对类进行修改。

【讨论】:

    猜你喜欢
    • 2011-05-25
    • 2020-06-10
    • 2012-05-14
    • 2023-04-06
    • 1970-01-01
    • 2013-01-17
    • 1970-01-01
    • 2011-09-26
    相关资源
    最近更新 更多