クラスモジュールを用いた自作クラスのプロパティについて

クラスモジュールの使い方を練習するため、遊び半分にプログラムしてみた。
高橋麻奈さんの『やさしいJava』に倣って、車オブジェクトを作るという体で。

f:id:akashi_keirin:20170107135025j:plain


とりあえず、Sheet1に、上の画像のような表を作る。
A、B列の1行目にはコマンドボタンを設置している。

まずは、「車クラス」の設計。

クラスモジュールを挿入し、「オブジェクト名」を「Car」にする。
f:id:akashi_keirin:20170107142247j:plain

クラスモジュールにコードを記述。

Option Explicit
'Field Variables
Private Number_ As Integer
Private Name_ As String
Private Gas_ As Double
Private Speed_ As Integer

'Accessor
Public Property Let Number(ByVal New_Number As Integer)
    If CStr(New_Number) <> "" Then
        Number_ = New_Number
    End If
End Property

Public Property Get Number() As Integer
    Number = Number_
End Property

Public Property Let Name(ByVal New_Name As String)
    If New_Name <> "" Then
        Name_ = New_Name
    End If
End Property

Public Property Get Name() As String
    Name = Name_
End Property

Public Property Let Gas(ByVal New_Gas As Double)
    If New_Gas < 0 Then
        MsgBox "ガソリン量がマイナスて……。"
        MsgBox "ふざけるなボケーーー!", vbCritical
        MsgBox "     _________" & vbCrLf & _
        " /          \ " & vbCrLf & _
        "/ /・\  /・\    \" & vbCrLf & _
        "|   ̄ ̄    ̄     | ち~んw" & vbCrLf & _
        "|    (_人_)    |" & vbCrLf & _
        "|     \     |          |" & vbCrLf & _
        "\      \_|     /"
        End
    ElseIf New_Gas > 100 Then
        MsgBox "そんなにガソリンが入るかい、ボケ!", vbCritical
        MsgBox "     _________" & vbCrLf & _
        " /          \ " & vbCrLf & _
        "/ /・\  /・\    \" & vbCrLf & _
        "|   ̄ ̄    ̄     | ち~んw" & vbCrLf & _
        "|    (_人_)    |" & vbCrLf & _
        "|     \     |          |" & vbCrLf & _
        "\      \_|     /"
        End
    Else
        If CStr(New_Gas) <> "" Then
            Gas_ = New_Gas
        End If
    End If
End Property

Public Property Get Gas() As Double
    Gas = Gas_
End Property

Public Property Let Speed(ByVal New_Speed As Integer)
    If New_Speed < 0 Then
        MsgBox "スピードがマイナスて……。"
        MsgBox "ふざけるなボケーーー!", vbCritical
        MsgBox "     _________" & vbCrLf & _
        " /          \ " & vbCrLf & _
        "/ /・\  /・\    \" & vbCrLf & _
        "|   ̄ ̄    ̄     | ち~んw" & vbCrLf & _
        "|    (_人_)    |" & vbCrLf & _
        "|     \     |          |" & vbCrLf & _
        "\      \_|     /"
        End
    ElseIf New_Speed > 400 Then
        MsgBox "そんなスピード出るか、ボケ!", vbCritical
        MsgBox "     _________" & vbCrLf & _
        " /          \ " & vbCrLf & _
        "/ /・\  /・\    \" & vbCrLf & _
        "|   ̄ ̄    ̄     | ち~んw" & vbCrLf & _
        "|    (_人_)    |" & vbCrLf & _
        "|     \     |          |" & vbCrLf & _
        "\      \_|     /"
        End
    Else
        If CStr(New_Speed) <> "" Then
            Speed_ = New_Speed
        End If
    End If
End Property

Public Property Get Speed() As Integer
    Speed = Speed_
End Property

'Constructer
Private Sub Class_Initialize()
    Number_ = 0
    Name_ = "名無し"
    Gas_ = 0#
    Speed_ = 4
End Sub

'Methods
Public Sub showCar()
    MsgBox "車・" & Name & "の" & vbCrLf & _
           "ナンバーは、" & Number & "、" & vbCrLf & _
           "ガソリンは、" & Gas & "リッターです。" & vbCrLf & _
           "本気を出せば、" & Speed & " km/hで走ります。"
End Sub

Public Sub runCar()
    If Me.Gas <> 0 Then
        MsgBox Name & "行きま~す!" & vbCrLf & _
            Me.Speed & " km/hでぶっ飛ばすぜ!" & vbCrLf & _
            "ぶおおおおおん!"
        If Me.Gas > Me.Speed * 0.1 Then
            Me.Gas = Me.Gas - Me.Speed * 0.1
        Else
            Me.Gas = 0
            MsgBox "ぷすん!……" & vbCrLf & _
               "ガソリンがなくなったようだ……。"
        End If
        MsgBox Me.Name & "のガソリン量が、" & Me.Gas & _
               "リッターになりました。"
    Else
        MsgBox Name & "行きま~す!" & vbCrLf & _
               Me.Speed & " km/hでぶっ飛ばすぜ!" & vbCrLf & _
               "ぷすん!……" & vbCrLf & _
               "ガソリンがないようだ……。"
    End If
End Sub


「Car」というオブジェクトに「Number」「Name」「Gas」「Speed」というプロパティを設置したわけだ。
「Number」を例に取ると、次のようなコードで実装していることになる。

Private Number_ As Integer    'クラス内での値保持用変数
Public Property Let Number(ByVal New_Number As Integer)    '値設定用プロシージャ
    Number_ = New_Number
End Property
Public Property Get Number() As Integer    '値取得用プロシージャ
    Number = Number_
End Property

Carクラスを使うには、変数を宣言して、New演算子インスタンス化すれば良い。
以後、その変数をオブジェクトとして使用できる。

たとえば、プロシージャ内で、

Dim car1 As Car    'Carクラス型の変数car1を宣言

と宣言し、

Set car1 = New Car

とすれば、以後「car1」をオブジェクトとして扱えるということ。

で、本題。

オブジェクトcar1のNumberプロパティに値を設定するときは、当然、たとえば

car1.Name = 1234

などとすれば良い。

で、大切なのは、このときにどんな処理が為されているか、という流れを理解しておくこと。

順を追って書いておこう。

【プロパティへの値の設定】
  1. car1.Name = 1234 が実行される→Property Let Name プロシージャに1234が渡される
  2. Property Let Nameプロシージャの仮引数New_Nameが1234を受け取る
  3. Private変数Name_に1234が代入される
【プロパティからの値の取得】

※たとえば、car1オブジェクトのNameプロパティをメッセージボックスに表示するとしよう。

  1. Msgbox car1.Name が実行される。
  2. car1のNameプロパティを取得するためにProperty Get Nameプロシージャに処理が移る
  3. Nameプロパティの値はPrivate変数Name_に入っているので、NameプロパティにName_の値(1234)を代入する
  4. car1.Nameの値として「1234」を得て、メッセージボックスには「1234」が表示される。

という流れで値を設定したり、取得したりしている。

値の設定と取得の際に、一旦Private変数を噛ますというのは一見無駄なようだが、使いようによってはいろいろ便利だったりする。

追記

2018年2月25日時点での考えを追記します。

  • 「プロパティ」に値が入っているのではなくて、あくまでも値を持っているのはPrivate変数。
  • 従って、変数が持っている値は、他のモジュールからは設定することも取得することもできない。
  • 要するに、設定する場合はProperty Let、取得する場合はProperty Getを介する他ない。
  • プロパティに値を代入しようとしたとき、すなわち、たとえば、
    car1.Name = "hoge"
    
    が評価されるときに引数「hoge」を渡してProperty Letが実行され、Private変数Name_に「hoge」が代入される、ということ。
  • 逆に、プロパティが参照されたとき、すなわち、たとえば、
    str = car1.Name
    
    が評価されるときには、Property Getが実行され、Private変数Name_にぶち込まれている値が返って、変数strにぶち込まれる、ということ。

このしくみによって、仮にプロパティの値を設定/取得する手続きが相当複雑だったとしても、コーディング時には、変数に値をぶち込んだり、変数から値を取り出すかのようにカンタンにプロパティを使うことができる、ということ。

このあたり、実際に使ってみないといまいちピンと来にくいと思うが、たとえば、

akashi-keirin.hatenablog.com

このように、レジストリの値を設定/取得するようなめんどくさそうなことでも、ひとたびPropertyにしてしまえばアホみたいにカンタンに実行できることになる。

複数のモジュールをまたがるような処理があるとき、Public変数を使う代わりにPropertyの使用を検討してみてはいかがだろうか。