エクセルVBA オブジェクト指向備忘録 親子クラスから子クラスのプロパティとメソッド使用

20241215エクセルVBA オブジェクト指向備忘録 親子クラスから子クラスのプロパティとメソッド使用

<前書き>
エクセルVBAオブジェクト指向、初心者です。
VBA自体は、以前から使用していました。
オブジェクト指向というものがあることは、知っていましたが、ネットなどを見てもよく分からず、挫折した過去あり。
<以上前書き>

 

まとまってませんが、自分用の備忘録。(不都合があれば、削除いたします。)
注:前回と同様に、moneyやyenを使ってますが、前回の記事とは内容が違います。

 

目的:

親クラスから子クラスを参照できるようにコーディングを書いてみる。(GPT4o様に依頼)

(1)
基本モジュールから、親クラスを通して、子クラスのプロパティを取得するコード

(2)
基本モジュールから、親クラスを通して、子クラスのメソッドを使えるコード

 

 


下記のコードを実行するとこのような実行結果になります。

--------------------------------------
Country: Japan
Conversion Rate to USD: 0.007
--------------------------------------

========================================コード
'main
Sub TestMoneyAndYen()
    ' 親クラスのインスタンスを作成
    Dim moneyInstance As money
    Set moneyInstance = New money

    ' 親クラスのプロパティを設定
    moneyInstance.MoneyCurrency = "Yen"
    moneyInstance.Amount = 1000

    ' 子クラスのインスタンスを作成
    Dim yenInstance As yen
    Set yenInstance = New yen

    ' 親クラスに子クラスを設定
    moneyInstance.SetChild yenInstance

    ' 親クラス経由で子クラスのプロパティを取得
    Dim countryName As String
    countryName = moneyInstance.GetChildProperty("Country")
    Debug.Print "Country: " & countryName

    ' 親クラス経由で子クラスのメソッドを呼び出す
    Dim conversionRate As Double
    conversionRate = moneyInstance.CallChildMethod("ConvertToUsd")
    Debug.Print "Conversion Rate to USD: " & conversionRate
End Sub

===============================================
' money.cls
Private pMoneyCurrency As String
Private pAmount As Double
Private pChild As Object ' 子クラスを保持する変数

' 通貨名プロパティ
Public Property Get MoneyCurrency() As String
    MoneyCurrency = pMoneyCurrency
End Property

Public Property Let MoneyCurrency(Value As String)
    pMoneyCurrency = Value
End Property

' 金額プロパティ
Public Property Get Amount() As Double
    Amount = pAmount
End Property

Public Property Let Amount(Value As Double)
    pAmount = Value
End Property

' 子クラスを設定するメソッド
Public Sub SetChild(ByVal Child As Object)
    Set pChild = Child
End Sub

' 子クラスのプロパティを取得するメソッド
Public Function GetChildProperty(ByVal PropertyName As String) As Variant
    If Not pChild Is Nothing Then
        Select Case PropertyName
            Case "Country"
                GetChildProperty = pChild.Country
            Case Else
                GetChildProperty = "Unknown Property"
        End Select
    Else
        GetChildProperty = "No Child Set"
    End If
End Function

' 子クラスのメソッドを呼び出すメソッド
Public Function CallChildMethod(ByVal MethodName As String) As Variant
    If Not pChild Is Nothing Then
        Select Case MethodName
            Case "ConvertToUsd"
                CallChildMethod = pChild.ConvertToUsd
            Case Else
                CallChildMethod = "Unknown Method"
        End Select
    Else
        CallChildMethod = "No Child Set"
    End If
End Function


====================
' yen.cls
Private pCountry As String
Private pConversionRate As Double

' コンストラクタ的メソッド(Initialize代替)
Private Sub Class_Initialize()
    pCountry = "Japan"
    pConversionRate = 0.007 ' 円→ドルの換算レート
End Sub

' 国名プロパティ
Public Property Get Country() As String
    Country = pCountry
End Property

' 換算メソッド
Public Function ConvertToUsd() As Double
    ConvertToUsd = pConversionRate
End Function
=====================

下記はクラスの構成

//////////////////////////////////////
解説1
メイン文で、 ' 親クラスのインスタンスを作成している。(親クラスというが、疑似的な親子です。)
    Dim moneyInstance As money
    Set moneyInstance = New money

次に、メイン文で、' 親クラスのプロパティを設定している。
    moneyInstance.MoneyCurrency = "Yen"
    moneyInstance.Amount = 1000


moneyのクラスを見ると、moneyにMoneyCurrencyとAmountのプロパティがある・・・。
(あれ?子クラスに入れた方がいいのではないの?)

メイン文で、次に、 ' 子クラスのインスタンスを作成を作成している。
    Dim yenInstance As yen
    Set yenInstance = New yen

次に、メイン文で、' 親クラスに子クラスを設定
    moneyInstance.SetChild yenInstance


moneyのクラスを見ると、' 子クラスを設定するメソッドがある。
Public Sub SetChild(ByVal Child As Object)
    Set pChild = Child
End Sub
これで、親クラスに、「空(未設定)の子クラス」がセットされた・・・。
「空(未設定)の子クラス」と書いたが、子クラスには、インスタンス化された時点で、
    pCountry = "Japan"
    pConversionRate = 0.007 ' 円→ドルの換算レート
が設定されている。
(property letがないので、書き換え不可な固定値。)


メイン文で、次に、  ' 親クラス経由で子クラスのプロパティを取得している。
    Dim countryName As String
    countryName = moneyInstance.GetChildProperty("Country")
    Debug.Print "Country: " & countryName

というか、moneyのクラスを見ると、
' 子クラスのプロパティを取得するメソッド
Public Function GetChildProperty(ByVal PropertyName As String) As Variant
として、自分(money)の中に入っているものを返している。
(これが(1)の答え)

メイン文で、次に、' 子クラスのメソッドを呼び出すメソッド
Public Function CallChildMethod(ByVal MethodName As String) As Variant
として、自分(money)の中に入っているものを返している。
(これが(2)の答え)


うーん。親クラス内に子クラスをインスタンス化して、子クラスのプロパティもメソッドも親クラスのメソッドで呼びだしている。
なんかイメージが違う。

///////////////////////////////////
追加
==========================
上記をまねて、yenクラスの他に、dollarクラスを作成する
==========================
' dollar.cls
Private pCountry As String
Private pConversionRate As Double

' コンストラクタ的メソッド(Initialize代替)
Private Sub Class_Initialize()
    pCountry = "America"
    pConversionRate = 150 ' ドル→円の換算レート
End Sub

' 国名プロパティ
Public Property Get Country() As String
    Country = pCountry
End Property

' 換算メソッド
Public Function ConvertToUsd() As Double
    ConvertToUsd = pConversionRate
End Function

==========================

 dollar.clsが実行されるように、メイン文を追加する。
==========================
'main
Sub TestMoneyAndYen()
    ' 親クラスのインスタンスを作成
    Dim moneyInstance As money
    Set moneyInstance = New money

    ' 親クラスのプロパティを設定
    moneyInstance.MoneyCurrency = "Yen"
    moneyInstance.Amount = 1000

    ' 子クラスのインスタンスを作成
    Dim yenInstance As yen
    Set yenInstance = New yen

    ' 親クラスに子クラスを設定
    moneyInstance.SetChild yenInstance

    ' 親クラス経由で子クラスのプロパティを取得
    Dim countryName As String
    countryName = moneyInstance.GetChildProperty("Country")
    Debug.Print "Country: " & countryName

    ' 親クラス経由で子クラスのメソッドを呼び出す
    Dim conversionRate As Double
    conversionRate = moneyInstance.CallChildMethod("ConvertToUsd")
    Debug.Print "Conversion Rate to USD: " & conversionRate
    
    
    
    ' 親クラスのプロパティを設定(書き換え)
    moneyInstance.MoneyCurrency = "dollar"
    moneyInstance.Amount = 7
    
    
    ' 子クラスのインスタンスを作成(追加)
    Dim dollarInstance As dollar
    Set dollarInstance = New dollar
    
    
    ' 親クラスに子クラスを設定(子のインスタンスを変更)
    moneyInstance.SetChild dollarInstance
    
    
    ' 親クラス経由で子クラスのプロパティを取得(変数宣言以外そのまま)
'    Dim countryName As String
    countryName = moneyInstance.GetChildProperty("Country")
    Debug.Print "Country: " & countryName

    ' 親クラス経由で子クラスのメソッドを呼び出す(変数宣言以外そのまま)
'    Dim conversionRate As Double
    conversionRate = moneyInstance.CallChildMethod("ConvertToUsd")
    Debug.Print "Conversion Rate to USD: " & conversionRate
End Sub
==========================

解説2
main文の重要なところは以下の箇所です。

    ' 親クラスのプロパティを設定(書き換え)
    moneyInstance.MoneyCurrency = "dollar"
    moneyInstance.Amount = 7

    ' 子クラスのインスタンスを作成(追加)
    Dim dollarInstance As dollar
    Set dollarInstance = New dollar

    ' 親クラスに子クラスを設定(子のインスタンスを変更)
    moneyInstance.SetChild dollarInstance

①親にのみあるプロパティの設定変更。
②子のインスタンスを設定
③②で作った子のインスタンスを親に設定

上記で、重要なのが、親moneyクラスの下記のコード。
' 子クラスを設定するメソッド
Public Sub SetChild(ByVal Child As Object)
    Set pChild = Child
End Sub
子クラスのインスタンスをpChildとして、親クラスが保持。
これで、どんな子クラスのインスタンスがセットされても、このコードなら、
moneyの子クラスのプロパティ・メソッドを取得するコードの書き換えが可能になり、
メイン文以外は、隠ぺいされる?ことになる。はず。

何となくややこしい感じになった。これで保守性が高まるのか???