t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

VBA モデル化の概念を理解すると、クラスモジュールの使い方が分かる

クラスモジュールを使いこなすためには、モデル化という概念をおさえておくと分かりやすい。しかしいきなりモデル化といわれても何のことかわからないと思うので、順を追って説明していく。

まずプログラミングにおけるモデル化の話をする前に、モデルという言葉の定義を押さえておこう。

モデルとは

Weblioでmodelを検索すると、次のように表示された。

主な意味:模型、モデル、ひな形、(原型の)塑像、原形、(理解などの)模型、(服装品・自動車などの)…型、(人・ものの)模範、手本、鑑(かがみ)

コア:型にはめるもの;ひな型

ejje.weblio.jp

このうちプログラミングで扱うモデルは、「(理解などの)模型」の意味である。
物事を理解するために、その性質を抜き出して構造図にしたものだと考えるとよい。

モデルは実際の物事から必要な情報だけをピックアップして簡略化したものである。

必要な情報は、そのプログラムが何を扱うかによって変わる。たとえば同じ個人情報でも服屋さんなら身長や胸囲など体格に関する情報がメインになるだろうし、病院なら血圧、血液型、アレルギーなど健康に関する情報を扱うことになる。歯医者なら歯の一本ずつを情報として扱う必要があるだろう。

まぁそのような特殊な例はさておき、とりあえず今回は一般的と思われる4つの情報で人物をモデル化してみた。
その図がこちら。
f:id:t-hom:20160929061736p:plain

人物に、氏名・住所・生年月日・性別が順序関係なくぶら下がっている。
これらの情報はどれも等しくその人物が持つ性質であり、そこに順序性は存在しない。

モデルをExcelの表に変換する

あるモデルをExcelの表で表現しようとすると、その性質上どうしても格納順を決める必要がある。
以下にサンプル表を書いてみた。

氏名 住所 生年月日 性別
山田太郎 大阪 2000/01/01
佐藤次郎 東京 2001/02/02
鈴木花子 愛知 2002/03/03

左から1番目が氏名、2番目が住所、3番目が生年月日、4番目が性別となっている。

モデルにはそうした順序構造や座標(アドレス)などは存在しないが、データをExcel表に落とし込む以上はどうしても順序を決めざるを得ないのである。

データの形として、理想はモデル、現実は表といったところだ。
あるいは、モデルに表という現実的な制約を与えることでようやくデータの形で利用できるという理解でもよいかもしれない。

さて、たとえば表から別の形式の表へ転記するようなマクロを考えてみる。
f:id:t-hom:20160929205844p:plain

このとき表は座標を持っているので、表から表への転記は座標から座標への転記となる。
f:id:t-hom:20160929210129p:plain

これは、VBAで書くとこういうコードになる。

Sub 転記()
    Dim 転記元 As Worksheet: Set 転記元 = Sheets("転記元")
    Dim 転記先 As Worksheet: Set 転記先 = Sheets("転記先")
    
    For i = 2 To 4
        転記先.Cells(1, i).Value = 転記元.Cells(i, 1).Value
        転記先.Cells(2, i).Value = 転記元.Cells(i, 4).Value
        転記先.Cells(3, i).Value = 転記元.Cells(i, 3).Value
        転記先.Cells(4, i).Value = 転記元.Cells(i, 2).Value
    Next
End Sub

これは表Aから人物情報を読み取って、その人物情報を表Bにコピーするという処理である。このときふつう、「氏名は転記元の1列目、転記先では1行目」「住所は転記元の2列目、転記先では4行目」といったことを考えながらコードを書く。

つまりプログラマーの頭の中には、「人物情報」というモデルが存在しているはずである。

図で表すと、こういう感じ。
f:id:t-hom:20160929070642p:plain

しかしコードに書かれているのは、あくまで座標から座標だけであり、後日コードを見返したときに注意深く読まなければ何をやっているのかサッパリわからなくなる恐れがある。

クラスモジュールでモデルを扱う

さて、ここからが本題だ。

まずクラスモジュールを挿入し、オブジェクト名を人物としておく。そして追加した人物クラスのコードはこちらを入力する。

Public 氏名 As String
Public 住所 As String
Public 生年月日 As Date
Public 性別 As String

こういう状態↓
f:id:t-hom:20160929211520p:plain

それから標準モジュールには以下を張り付ける。

Sub モデルを介した転記()
    Dim 転記元 As Worksheet: Set 転記元 = Sheets("転記元")
    Dim 転記先 As Worksheet: Set 転記先 = Sheets("転記先")
    
    Dim m As 人物
    For i = 2 To 4
        Set m = New 人物
        m.氏名 = 転記元.Cells(i, 1).Value
        m.住所 = 転記元.Cells(i, 2).Value
        m.生年月日 = 転記元.Cells(i, 3).Value
        m.性別 = 転記元.Cells(i, 4).Value
        
        転記先.Cells(1, i).Value = m.氏名
        転記先.Cells(2, i).Value = m.性別
        転記先.Cells(3, i).Value = m.生年月日
        転記先.Cells(4, i).Value = m.住所
    Next
End Sub

実行するとうまく転記できているのがわかる。

もう一度さっきの図と、コードを見比べてみよう。
f:id:t-hom:20160929070642p:plain
f:id:t-hom:20160929211905p:plain

このように、実際に行っていることとコードが一致している。

ふつうの変数を使った方法と、クラスを使った方法と何が違うのか

ここで「ふつうの変数と何が違うの?」と思われたかもしれない。
そのとおり。わざわざ面倒なクラスなんて使わなくても以下のように普通の変数でも似たようなことができる。

Sub 変数を介した転記()
    Dim 転記元 As Worksheet: Set 転記元 = Sheets("転記元")
    Dim 転記先 As Worksheet: Set 転記先 = Sheets("転記先")
    
    Dim 氏名, 住所, 生年月日, 性別
    For i = 2 To 4
        氏名 = 転記元.Cells(i, 1).Value
        住所 = 転記元.Cells(i, 2).Value
        生年月日 = 転記元.Cells(i, 3).Value
        性別 = 転記元.Cells(i, 4).Value
        
        転記先.Cells(1, i).Value = 氏名
        転記先.Cells(2, i).Value = 性別
        転記先.Cells(3, i).Value = 生年月日
        転記先.Cells(4, i).Value = 住所
    Next
End Sub

しかし変数というのはあくまでそれぞれが単体で存在しているものであり、そこに構造的な結びつきはない。氏名・住所・生年月日・性別は確かに人物の情報であるが、それをプログラム上で結びつけるものが無いのだ。

クラスモジュールを使えばこれらは人物オブジェクトに対する属性として強固に結びつく。

また、クラスモジュールでモデルを扱うと、こんな風にコレクションにモデルを追加してモデルの束を作り、それを別表に転記するという方法も可能になる。

Sub モデルを介した転記2()
    Dim 転記元 As Worksheet: Set 転記元 = Sheets("転記元")
    Dim 転記先 As Worksheet: Set 転記先 = Sheets("転記先")
    
    Dim m As 人物
    Dim People As Collection
    Set People = New Collection
    
    'モデルの束を作成
    For i = 2 To 4
        Set m = New 人物
        m.氏名 = 転記元.Cells(i, 1).Value
        m.住所 = 転記元.Cells(i, 2).Value
        m.生年月日 = 転記元.Cells(i, 3).Value
        m.性別 = 転記元.Cells(i, 4).Value
        People.Add m
    Next
    
    'モデルの束から転記
    cnt = 2
    For Each m In People
        転記先.Cells(1, cnt).Value = m.氏名
        転記先.Cells(2, cnt).Value = m.性別
        転記先.Cells(3, cnt).Value = m.生年月日
        転記先.Cells(4, cnt).Value = m.住所
        cnt = cnt + 1
    Next
End Sub

このようにデータをモデル化して扱うことができるのがクラスモジュールを使うメリットの一つである。

まとめ

さて、今回はモデル化の概念を抽象的な図をつかって説明した。
またモデルをコード上で表現するためにクラスモジュールが適していることがご理解いただけたかと思う。

さらにクラスモジュールのメリット・活用方法を学ぶには以下の記事もおススメ。
thom.hateblo.jp

また、便利なのはわかったけど実際クラスってどうつかうの?って方はこちらの記事が超おススメ!
ateitexe.com

このt-hom's diaryを参考にされたと書いてあるけど、私の記事より断然分かりやすくまとまっている!!

ま、私のブログはVBAマニア層に向けた小難しい記事が売りなので(笑

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。