データ転記マクロ~その3

前回のマクロをさらに書き換える。

今度は、無駄にクラスモジュールを使うよ。

クラスモジュールを挿入して、オブジェクト名を「GambleRacer」にした。

f:id:akashi_keirin:20170310212109j:plain

クラスモジュールには下記のコードを書く。

Option Explicit
'フィールド                              '……(1)
Private rcID_ As Long
Private rcClass_ As String
Private rcRank_ As String
Private rcName_ As String
Private rcTerm_ As String
Private rcPref_ As String
Private rcTactics_ As String
'アクセサ                                '……(2)
Public Property Get rcID() As Long
  rcID = rcID_
End Property
Public Property Get rcClass() As String
  rcClass = rcClass_
End Property
Public Property Get rcRank() As String
  rcRank = rcRank_
End Property
Public Property Get rcName() As String
  rcName = rcName_
End Property
Public Property Get rcTerm() As String
  rcTerm = rcTerm_
End Property
Public Property Get rcPref() As String
  rcPref = rcPref_
End Property
Public Property Get rcTactics() As String
  rcTactics = rcTactics_
End Property
'コンストラクタ
Private Sub Class_Initialize()            '……(3)
  With ActiveSheet
    rcID_ = .Range("B3").Value      'No.
    rcClass_ = .Range("B7").Value   '級
    rcRank_ = .Range("C7").Value    '班
    rcName_ = .Range("F3").Value    '氏名
    rcTerm_ = .Range("F5").Value    '期別
    rcPref_ = .Range("B5").Value    '登録
    rcTactics_ = .Range("F7").Value '戦法
  End With
End Sub
'メソッド

いつものように一応解説。

  • (1)でクラス内でのみアクセス可能なPrivate変数を準備。プロパティとの対応関係が分かりやすいようにプロパティ名に「_」(アンダースコア)を付けている。
    ※これは、そもそもはこの方を意味も分からずマネしてただけなんですけど、便利さが分かってからずっと使っています。
  • (2)はプロパティの値取得用のアクセサメソッドみたいなやつ。Propertyプロシージャという。
    Propertyプロシージャの挙動については、ずっと前に書いたコチラもどうぞ。
  • 今回はメンドクサイから、(3)みたいにコンストラクタ部分に書いたんですけど、ホントはメソッドとして書いた方がいいと思う。
    ※これだと他の場面で使い回しが効かないクラスになるよな……。
    あ、ちなみに「コンストラクタ」ってのはインスタンス生成時に自動的に実行されるメソッドのことで、VBAでは「~~_Initialize()」って名前ですな。

まあ、クラスモジュール使いでない人から見たら、

なんでこんなにめんどくせーことするんだ!?

ってところでしょうね。

めんどくせーことついでに、標準モジュールの宣言セクションに、

Public Enum rcData
  dtID = 1
  dtClass
  dtRank
  dtName
  dtTerm
  dtPref
  dtTactics
End Enum

こんなものも用意しておくよ。

さらに、同じく標準モジュールの宣言セクションで、

Public gr As GambleRacer

と、クラス用の変数を用意するのも忘れないようにしよう。

さて、ここまでで下ごしらえは完了。あとは、標準モジュールにメインのコードを書く。

Sub sendDataVer3()
  '作業フォルダパスを変数に格納
  Dim folderPath As String
  folderPath = ThisWorkbook.Path
  'アクティブシートを変数にセット
  Dim objSheet As Worksheet
  Set objSheet = ActiveSheet
  '個票ブックのファイル名を変数にセット
  Dim objFileName As String
  objFileName = objSheet.Parent.Name
  'データの転記
  Set gr = New GambleRacer                                      '……(1)
  With ThisWorkbook.Worksheets("集約")
    Dim tgtRow As Integer
    tgtRow = .Cells(Rows.Count, 1).End(xlUp).Row + 1
    .Cells(tgtRow, rcData.dtID).Value = gr.rcID           'No.  '……(2)
    .Cells(tgtRow, rcData.dtClass).Value = gr.rcClass     '級
    .Cells(tgtRow, rcData.dtRank).Value = gr.rcRank       '班
    .Cells(tgtRow, rcData.dtName).Value = gr.rcName       '氏名
    .Cells(tgtRow, rcData.dtTerm).Value = gr.rcTerm       '期別
    .Cells(tgtRow, rcData.dtPref).Value = gr.rcPref       '登録
    .Cells(tgtRow, rcData.dtTactics).Value = gr.rcTactics '戦法
  End With
  Set gr = Nothing
  '個票ファイルを閉じてフォルダ移動
  objSheet.Parent.Close False
  Name folderPath & "\" & objFileName As _
       folderPath & "\処理済\" & objFileName
End Sub

 

基本、前回のコードとほとんど同じ。変えたのは(1)のところと(2)以下の7行だけ。

  • (1)はおなじみ、GambleRacerクラスのインスタンス生成。
  • (2)以下の7行でデータ転記。

データ転記部分ですけど、メチャクチャ分かりやすいと思いませんか?

イコールの左辺部分では、セルの指定に列挙体を使用。意味のある文字列で指定しているので「A」(列符号)とか「1」(列番号)で指定されるのに比べて格段に読みやすいと思う。

イコールの右辺についても、意味のある名前で指定しているから「Range("A3").Value」とか言われるよりよっぽど分かりやすいと思う。

「この程度の処理にクラスモジュールを使うなんて……」と眉を顰める向きもあろうが、最初に余分な手間をかけるだけのネウチは十分すぎるほどにあると思うのですがいかがでしょうか。

@akashi_keirin on Twitter