t-hom’s diary

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

VBA クラスモジュールを気軽に使う その1

先日買った以下の書籍に取り組みはじめた。

アルゴリズム大事典 (I・O BOOKS)

アルゴリズム大事典 (I・O BOOKS)

序盤に足し算だけで掛け算をするという問題があるが、普通に書くとこのようになる。

Sub 足し算で乗算_ノーマル()
    a = 9
    b = 5
    Dim 合計 As Long
    For i = 1 To b
        合計 = 合計 + a
    Next
    Debug.Print 合計
End Sub

つまり、aをb回足せば良い。簡単だ。

ここで面倒くさいのは、「合計 = 合計 + a」という表記である。
人間は普通、「合計にaを足す」と表現する。
「合計に1を足したものを合計に代入する」などとまどろっこしい言い方はコンピューター特有のものだ。

VBAではこれが普通なのだが、VB.NETでは「合計 += a」と書ける。

この、X = X + AというパターンはVBAで頻繁に登場する。
そこで、これを少しでもスマートな書き方に近づけるため、以下のクラスを用意した。

クラス名は「Accumulator」としている。

Private PNumber As Long

Private Sub Class_Initialize()
    PNumber = 0
End Sub

Property Get Number() As Long
    Number = PNumber
End Property

Public Sub Clear()
    Call Class_Initialize
End Sub

Public Sub Add(x As Variant)
    PNumber = PNumber + x
End Sub

中身は分からなくても良い。単にクラスモジュールを挿入し、クラス名を変えて上記のコードを貼り付ければ良い。

これを使うと、メインのコードはこうなる。

Sub 足し算で乗算_累算機サンプル()
    a = 31
    b = 9
    Dim 合計 As New Accumulator
    For i = 1 To b
        合計.Add a
    Next
    Debug.Print 合計.Number
End Sub

合計変数の宣言文は長くなる。
そして数字を取り出すのに、.Numberとしなければならない。

それでも、「合計にaを足す」という人間の思考とマッチした書き方が出来るのは嬉しい。
オブジェクト指向の最大のメリットは内部の操作を隠蔽し、直感的に操作できるモノを作り出すことである。

Accumulatorの内部でどういう計算がされているかは一切考える必要は無い。
ただAddすれば値を加えることが出来、.Numberで取り出せる。ただそれだけ知っていれば使える。

さらに、.Numberと指定するのが面倒であれば、デフォルトプロパティを作成するというテクニックがある。
これは過去記事に書いたのでそちらを参照して欲しい。
thom.hateblo.jp

このテクニックを使うと、.Numberがデフォルトプロパティとなるため、ただ「合計」と書けば数値を参照できる。

Sub 足し算で乗算_累算機サンプル2()
    a = 31
    b = 9
    Dim 合計 As New Accumulator
    For i = 1 To b
        合計.Add a
    Next
    Debug.Print 合計
End Sub

今回のサンプルは小さいので、わざわざクラスを作成するメリットは小さいと感じるかもしれない。
もう少しクラスを強化してみよう。

今度はいろんな演算ができるようにしたのでクラス名も「OperatableNumber」とした。

Private PNumber As Double

Private Sub Class_Initialize()
    PNumber = 0
End Sub

Property Get Number() As Long
    Number = PNumber
End Property

Property Let Number(x As Long)
    PNumber = x
End Property

Public Sub Clear()  'ゼロに戻す
    Call Class_Initialize
End Sub

Public Sub Add(x As Variant)    '引数を足す
    PNumber = PNumber + x
End Sub

Public Sub Substruct(x As Variant)  '引数を引く
    PNumber = PNumber - x
End Sub

Public Sub Times(x As Variant)    '引数を掛ける
    PNumber = PNumber * x
End Sub

Public Sub Devides(x As Variant)    '引数で割る
    PNumber = PNumber / x
End Sub

Public Sub Plus()   '1足す
    PNumber = PNumber + 1
End Sub

Public Sub Minus()  '1引く
    PNumber = PNumber - 1
End Sub

Public Sub Half()   '半分にする
    PNumber = PNumber / 2
End Sub

Public Sub Twice()  '2倍にする
    PNumber = PNumber * 2
End Sub

そしてそのクラスを使用するサンプルがこちら
※デフォルトプロパティのテクニックも使用しています。

Sub クラス使用サンプル()
    Dim X As New OperatableNumber
    Debug.Print "初期値:"; X
    X = 1
    Debug.Print X
    X.Add 3
    Debug.Print X
    X.Half
    Debug.Print X
    X.Times 5
    Debug.Print X
    For i = 1 To 5
        X.Plus
    Next
    Debug.Print X
    X.Minus
    Debug.Print X
End Sub

自分専用のクラスを作っておくと、便利なオブジェクトとしていろんなコードで使いまわしできる。

以下のように取り扱い説明書を用意すれば、誰でも使える。

OperatableNumberのトリセツ

まず、OperatableNumber.clsファイルをインポートしておきます。
コードで使用する場合は、最初にOperatableNumber型で変数を宣言してください。

Integer型やLong型の変数を作るときと同じですが、ひとつだけ、「New」というおまじないが必要です。
例) Dim X As New OperatableNumber

あとは普通の変数と同じように代入や参照ができます。
例) X = 1 : MsgBox X

値を加えるときは従来どおり、X = X + 10などと書くこともできますが、Add命令を使うと、X.Add 10というふうにシンプルに書けます。
他にも以下のような命令があります。

X.Add 10 Xに10を加える
X.Plus Xに1を加える
X.Minus Xから1を引く
X.Times 5 Xを5倍する
X.Half Xを半分にする

まとめ

クラスモジュールを使いこなせるようになると、コーディングの幅が広がる。
ExcelのSheetやRangeもオブジェクトなので、自分でクラスを作れるようになるとより理解が深まる。
使えば慣れるし、ここぞという場面でどんどん閃くようになるだろう。
こういう小さなことでも、もっと気軽にクラスを使って良いと思う。

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