VBAには標準モジュールのほかに、クラスモジュールというものがある。
クラスモジュールについて調べようと思っても日本の書籍ではあまりきちんと解説されておらず、主にネットから情報を得ることになる。
使い方についてはまだ情報が存在するのだが、「使いどころ」については実際に活用している方が少ないせいか、ほとんど紹介しているサイトを見かけない。
今回は比較的身近に活用されているであろうExcelで作られた一覧表を題材に、クラスモジュールの使いどころを紹介したい。
※使い方が分からないという方はこちらをご参照ください。
thom.hateblo.jp
さて、今回は適当なデータが無かったので「なんちゃって個人情報」を使用して説明する。
これほんと便利。
このような一覧表のそれぞれの行をレコードと呼ぶ。
今回利用するなんちゃって個人情報では、ひとつのレコードは、ひとりの人物を表す。
このひとりひとりの人物情報をオブジェクトとして扱い、コレクションに格納してしまうと、あとあと活用が楽になる。
その解説の前にまず、クラスモジュールを使わないバージョンを紹介しておこう。
コードはこちら。
Sub カレーの食べ方アンケート() For i = 2 To 100 Debug.Print Range("I" & i).Value; "在住"; Debug.Print DateDiff("yyyy", CDate(Range("F" & i)), Date); "歳"; Debug.Print Range("D" & i).Value; "性 "; Range("M" & i); "性" Next End Sub
実行すると、このように表示される。
(あ…最後の性は余計だった。。まあ、SS取ってしまったのでこのままにしておく)
これはステップ数も少なくて分かりやすいコードだ。
年齢を誕生日から計算で求めているのは、表に書かれている年齢はどんどん古くなっていくためだ。
次にオブジェクトコレクションを作成するバージョン。
まずはクラスモジュールPersonを用意し、次のコードを記入する。
Public 名前 As String Public ふりがな As String Public アドレス As String Public 性別 As String Public 誕生日 As Date Public 婚姻 As String Public 血液型 As String Public 都道府県 As String Public 電話番号 As String Public 携帯 As String Public キャリア As String Public カレーの食べ方 As String Public Property Get 年齢() As Integer 年齢 = DateDiff("yyyy", 誕生日, Date) End Property Public Property Get Self() As Person Set Self = Me End Property
次に標準モジュールに書くメインのコード。
Enum 列 名前 = 1 ふりがな アドレス 性別 年齢 誕生日 婚姻 血液型 都道府県 電話番号 携帯 キャリア カレーの食べ方 End Enum Sub カレーの食べ方アンケート結果() Dim sh As Worksheet Set sh = ThisWorkbook.Sheets("なんちゃって個人情報") Dim Persons As New Collection Dim i As Long For i = 2 To 100 With New Person .名前 = sh.Cells(i, 列.名前) .ふりがな = sh.Cells(i, 列.ふりがな) .アドレス = sh.Cells(i, 列.アドレス) .性別 = sh.Cells(i, 列.性別) .誕生日 = sh.Cells(i, 列.誕生日) .婚姻 = sh.Cells(i, 列.婚姻) .血液型 = sh.Cells(i, 列.血液型) .都道府県 = sh.Cells(i, 列.都道府県) .電話番号 = sh.Cells(i, 列.電話番号) .携帯 = sh.Cells(i, 列.携帯) .キャリア = sh.Cells(i, 列.キャリア) .カレーの食べ方 = sh.Cells(i, 列.カレーの食べ方) Persons.Add .Self End With Next 'Personsコレクションからひとりずつ取り出してプロパティを出力 Dim p As Person For Each p In Persons Debug.Print p.都道府県; "在住"; p.年齢; "歳"; p.性別; "性 ", p.カレーの食べ方 Next End Sub
最初のEnumからしてよく分からないかもしれないが、過去記事で解説しているのでそちらを参照してほしい。
thom.hateblo.jp
このコードは、最初のFor文(For i = 2 To 100)が終わるまではすべて準備である。
準備だけで元のコードの何倍も長い。
これのどこが良いコードなんだろうか。
実は、一旦レコードをオブジェクトに格納することによって、各段にコーディングがしやすくなるのだ。
たとえば、大阪府在住の方だけ出力したいとすると、「If p.」と入力した時点で、プロパティの候補が出る。
ここで都道府県を選んでTabキーで決定し、条件式を書き足す。
Dim p As Person For Each p In Persons If p.都道府県 = "大阪府" Then Debug.Print p.都道府県; "在住"; p.年齢; "歳"; p.性別; "性 ", p.カレーの食べ方 End If Next
これだけで次のとおり、大阪府在住の方だけが取り出せる。
一方、非オブジェクト指向のコードを同様に変更しようと思ったらこのように条件を足してやれば良い。
Sub カレーの食べ方アンケート() For i = 2 To 100 If Range("I" & i).Value = "大阪府" Then Debug.Print Range("I" & i).Value; "在住"; Debug.Print DateDiff("yyyy", CDate(Range("F" & i)), Date); "歳"; Debug.Print Range("D" & i).Value; "性 "; Range("M" & i) End If Next End Sub
まだかろうじてシンプルさを維持している。
しかし、Range("XX")といった表記が増えてくると、それらが何を意味しているのかといった脳内変換でそのうち頭がパンクする。
では次に、苗字だけ取り出したい場合はどうするか。
データを見るとスペース区切りのようなので、Split関数に名前を渡して0番目のデータをとればよさそうだ。
非オブジェクト指向の場合はこうなる。
Sub カレーの食べ方アンケート() For i = 2 To 100 If Range("I" & i).Value = "大阪府" Then Debug.Print Range("I" & i).Value; "在住 "; Debug.Print Split(Range("A" & i).Value)(0); "さん"; Debug.Print DateDiff("yyyy", CDate(Range("F" & i)), Date); "歳"; Debug.Print Range("D" & i).Value; "性 "; Range("M" & i) End If Next End Sub
なにやらコードがごちゃごちゃしてきた。
一方オブジェクト指向の場合はどうするか。
まず、Personクラスに名字というプロパティを追加する。
Public Property Get 名字() As String 名字 = Split(名前)(0) End Property
するとMainコードで「p.」を入力した時点で、プロパティのリストから名字が選べる。
修正したメインコードはこちら。単にp.名字をとってくるだけで良い。
'Personsコレクションからひとりずつ取り出してプロパティを出力 Dim p As Person For Each p In Persons If p.都道府県 = "大阪府" Then Debug.Print p.都道府県; "在住 "; p.名字; "さん"; p.年齢; "歳"; p.性別; "性 ", p.カレーの食べ方 End If Next
項目が一つ増えただけで、何も難しくはなっていない。
何が増えたのかも一目瞭然である。これがオブジェクト指向の良いところである。
その他工夫できる点としては、例えば敬称の「さん」や、年齢の「歳」もプロパティの内部に押し込んでしまえば、メインコードで書く必要はなくなる。
Personsコレクションを作るまでは割と面倒くさいけれど、一度オブジェクトに落とし込んでしまえばメインコードの簡潔さを保ったままメンテナンスできるということがお分かりいただけたかと思う。
オブジェクト指向なんて自分には関係ないよと思われていた方も、これを機にオブジェクト指向に興味を持っていただけたら嬉しい。
2016/12/25追記
SelfプロパティについてYahoo知恵袋で質問いただいているようなので追記。
detail.chiebukuro.yahoo.co.jp
この記事を書く前に直近で以下の記事を挙げており、そちらが前提になっていた。
thom.hateblo.jp
検索経由で今回の記事のほうがアクセスが増えてしまったため混乱させてしまったようだ。申し訳ない。
私の記事じゃないけれど、こちらでも解説してくれてるのでどうぞ。
ateitexe.com
テクニックとしてはこちらもお勧め。
thom.hateblo.jp
クラスモジュールを扱っているVBA本
残念ながら日本の書籍ではまともにクラスモジュールを扱っているものは殆ど無い。
洋書なら以下の本が詳しいのでおススメである。
日本語の書籍では、以下の本がクラスモジュールに少しページを割いている。
(絶版書のため価格高騰。)