20240421 エクセルVBAクラス備忘録 メイン文の使い方
<前書き>
エクセルVBAオブジェクト指向、初心者です。
VBA自体は、以前から使用していました。
オブジェクト指向というものがあることは、知っていましたが、ネットなどを見てもよく分からず、挫折した過去あり。
<以上前書き>
(素人なので間違っているかもしれません。汗。)
今回、メイン処理について、思ったことのメモです。
大事な気がするので、きちんと書きたかったのですが、まとめる時間がなく(能力もなく)、なんとなくのイメージです。
何回か前の備忘録で、「メイン文に「全部のドメインオブジェクト(重要なクラスのインスタンス)」が見えないのは、分かりにくいのでは?」
といった主旨のことを書いて、メイン文に、ドメインオブジェクトを記載した回があります。
その後、考えたのですが、
メインから、クラスを呼んで、さらにそこから、他のクラスを呼ぶことはある。
・・・その場合、そうするのか?
とか悩みます。(まあ、自分が分かりやすかったらいいだけですが。)
で、【自分なりのルール】を考える。
今現在のスキルで考えていることやコードを書く上で、当たり前のことですが、メモ。
●クラスを使う場合、なるべくメイン文で、クラスをインスタンス化する
(一度インスタンス化したデータをメイン文内で追えるようにしておく)
●そのインスタンス化したデータを利用して、他の処理につなげる場合は、functionでメイン文にデータを持ってくる。
(よく利用するデータは深いところで処理しない(処理してもfunctionでメインに戻す))
●そのインスタンス化したデータを利用しない場合(一度切りの処理・中間処理など)、メインに戻さないでよい。
(クラスメソッドでインスタンス化して、そこで終了)(インスタンスが消える処理すればなお良い)
<以下実例>(例と言いながら、かなりややこしいです。)
エクセルシートは、前回同様、下記の通りです。
コードは、youtube「ひとりごとワンダーランド」様を参考に書いています。(←すごく感謝)
(不都合があれば削除いたします。)
////////////////////////////////////
メイン文
Sub 処理開始()
''シート読み込み
Dim v売上シート As 売上シートk
Set v売上シート = New 売上シートk
Dim v元データ As Variant ・・・①
v元データ = v売上シート.読み込み("売上") '売上はシート名 functionで戻し ・・・②
''売上データリスト作成
Dim v売上オブジェクト生成 As 売上オブジェクト生成k
Set v売上オブジェクト生成 = New 売上オブジェクト生成k
Dim v売上データリスト As 売上データリストk
Set v売上データリスト = v売上オブジェクト生成.リスト生成(v元データ) ・・・③④
End Sub
/////////////////////////////////////////////////////
'クラス「売上データ」
Private m名前 As String
Private m日付 As Date
Private m売上金額 As Long
Public Property Let 名前(p名前 As String)
m名前 = p名前
End Property
Property Get 名前() As String
名前 = m名前
End Property
Public Property Let 日付(p日付 As Date)
m日付 = p日付
End Property
Property Get 日付() As Date
日付 = m日付
End Property
Public Property Let 売上金額(p売上金額 As Long)
m売上金額 = p売上金額
End Property
Property Get 売上金額() As Long
売上金額 = m売上金額
End Property
/////////////////////////////////////////////////////
クラス「売上シート」
Public Function 読み込み(pシート名) As Variant
With ThisWorkbook.Worksheets(pシート名)
Dim hani As Range
Set hani = .Range("A2").CurrentRegion
Set hani = hani.Offset(1).Resize(hani.Rows.Count - 1)
読み込み = hani '標題除く 2次元配列
End With
End Function
/////////////////////////////////////////////////////
'クラス「売上オブジェクト生成」
Public Function リスト生成(v元データ As Variant) As 売上データリストk '←オブジェクトを返す
Dim v売上データリスト As 売上データリストk '←返したいデータオブジェクト
Set v売上データリスト = New 売上データリストk
Dim vRowCount As Long
For vRowCount = LBound(v元データ) To UBound(v元データ)
Dim v売上データ As 売上データk
Set v売上データ = New 売上データk
v売上データ.名前 = v元データ(vRowCount, 2) '順番変えた
v売上データ.日付 = v元データ(vRowCount, 1)
v売上データ.売上金額 = v元データ(vRowCount, 3)
Call v売上データリスト.追加(v売上データ)
Next vRowCount
Set リスト生成 = v売上データリスト
End Function
/////////////////////////////////////////////////////
'クラス「売上データリスト」
Private m売上データリスト As Collection 'private化。publicでなくProperty Get 取得で取り出し。
'letはないけどgetは作る。変数名Itemsとかでなくprivate変数(m売上データリスト)でcollection
Public Property Get 取得() As Collection
Set 取得 = m売上データリスト
End Property
Public Sub 追加(p売上データ As 売上データk)
If m売上データリスト Is Nothing Then
Set m売上データリスト = New Collection
End If
m売上データリスト.Add p売上データ
End Sub
解説メモ
①v元データという命名は気に入っています。名前からして重要そうでない。また、クラス名にも類似のものがない。
(variantで受けるので、多分配列ということが分かる。)
②クラス「売上シート」の読み込むメソッド(function)で、値(配列)を読み込みに入れて、さらに、メイン文のv元データに戻している。
(この使い方で、メイン文に、v元データオブジェクトをメインに戻している。データを続けて使うため。)
③④ Set v売上データリスト = v売上オブジェクト生成.リスト生成(v元データ)
ここでは最終的に、v元データ(配列)を売上データリスト(collectionオブジェクト)に、入れることをしている。
まず、 v売上オブジェクト生成.リスト生成(v元データ) の箇所について、
クラス「売上オブジェクト生成」では、リスト生成メソッド (function)がある。
そこで、配列v元データのデータ(1行分)をクラスv売上データ(1item)に入れている。
(クラスv売上データのプロパティ(日付・名前・売上金額))
上記処理のために、このクラス内で、クラス「v売上データ」をNewしているが、この「売上データ」オブジェクトは メイン文には表れない。メインに戻す必要はない。
続けて、このクラスでは、最終的に欲しい「売上データリスト」オブジェクトをNewするが、
Set v売上データリスト = New 売上データリストk
として「売上データ」クラスを使って、v売上データリストをNewしている。
で、この「売上データリスト」クラスは、collectionとして、設定されている。
そしてこの「売上データリスト」クラスには、追加メソッドを持っているので、
クラス「売上データリスト」の追加メソッドを使って、v売上データ(1item)を、
売上データリストにcollectionしていく。
で、上記で、できたものをfunctionで、メイン文のv売上データリストに戻して完了。
Set v売上データリスト = v売上オブジェクト生成.リスト生成(v元データ)
その他
クラスの命名については、もっと分かりやすくならないだろうか・・・(課題)
今回使用したクラスは、
・売上シート
・売上データ
・売上データリスト
・売上王ジェクト生成
と4つあるが、
売上データが、入れ物(プロパティの塊)で、売上データリストが、出すもの(collection)。
残りの売上シートは、配列用の範囲で、売上王ジェクト生成はfunction。
v元データは、ワークシート上にしかない。
各クラスがそんな機能・働きなのか分かりやすければ、もっといいかも。