VBA公共变量和属性之间的区别

Tox*_*iro 8 oop vba properties interface class

有什么区别

Public Variable As Integer
Run Code Online (Sandbox Code Playgroud)

Private pVariable As Integer

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

Public Property Get Variable()
    Variable = pVariable
End Property
Run Code Online (Sandbox Code Playgroud)

在VBA类模块中?

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

小智 21

尽管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
Run Code Online (Sandbox Code Playgroud)

错的有点不必要.

注意:您可以在需要处理错误/验证数据的情况下执行此操作,但通常如果设置和获取您不会这样做的值那么简单.

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

当你只需暴露其中一个属性而不是另一个属性(即只有setter或getter)时,故事会改变360度.通过一个例子可能更容易理解......

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

想象一下,你必须建立一个类来模拟银行账户.你需要一个方法depositwithdraw帐户的钱以及显示balance.

通常情况下,您不会setterbalance字段,因为应该允许任何人明确set表示余额.(如果你知道允许这样做的银行,请告诉我;)).实际余额应该是私人变量.应该有一个暴露它的财产,这就是你应该考虑的一切.

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

IAccountServices.cls

Sub Deposit(amount As Double)
End Sub

Sub WithDraw(amount As Double)
End Sub
Run Code Online (Sandbox Code Playgroud)

和另一个代表帐户的类

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
Run Code Online (Sandbox Code Playgroud)

注意:这显然是最简单的简单示例,它没有任何错误处理或检查余额是否足以撤销等.这仅用于演示目的,不用于实际应用程序.

通过这种封装,我立即看到/知道

  • 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
Run Code Online (Sandbox Code Playgroud)

要获得VBA OOP的介绍我可以推荐:

  • 正如hnk所指出的,仍然有正当理由使用`Let`和`Get`来简单地允许对其他私有变量进行错误检查.所以我不会说OPs代码是错误的**,只是有点不必要/非最佳.使用带有gets和let的私有变量对我来说似乎是一种好习惯,虽然我的学术背景是C++/C#所以它可能只是习惯的力量. (3认同)
  • 您可能仍希望使用`Let`和`Get`来封装以执行错误检查等.除非您出于严格的性能原因这样做(在这种情况下,您最好使用C++制作DLL然后引用它)最好通过错误检查或条件响应来保留选项以增强或改进类功能.但非常详细的解释,所以+1为此. (2认同)

rid*_*ill 6

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

Get属性可以计算实际上不存在于类中的"变量".例如,质量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
Run Code Online (Sandbox Code Playgroud)

一个财产可能会检查的有效性,如不接受负积.或者它可以保持对象的字段属性同步:

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

您还可以通过省略Let或Get属性将属性设置为只读(或只写 - 不要使用太多).

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