VBAを「スクリプト」から「エンジニアリング」へ昇華させる:カプセル化の真髄
多くのVBAエンジニアは、コードを書く際に「Public変数」の誘惑に負けてしまいます。`Public UserID As String` と宣言し、どこからでも値を書き換えられる状態にする。一見便利ですが、それは「時限爆弾をコードのあちこちに仕込んでいる」のと同じです。
なぜなら、値が変更された瞬間に何が起きるか、誰も追跡できないからです。
今日のテーマは、VBAにおける「Propertyプロシージャ」を用いたカプセル化です。これをマスターすれば、あなたの書くツールは「散らかったマクロ」から「堅牢な業務システム」へと劇的に進化します。
—
1. なぜ「Public変数」は悪なのか?
例えば、Excelから外部DBへデータを送るツールを作るとします。`UserID`が正しく設定されていないのに、誤った値のまま更新処理が走ったらどうなるでしょうか?
- Public変数: どこで、いつ、誰が書き換えたか追跡不可能。バグの原因特定に数時間を要する。
- Propertyプロシージャ: 書き込みの瞬間にバリデーション(妥当性チェック)を実行できる。不正な値は「門前払い」可能。
VBAにおいて、変数は「隠す」のがプロの流儀です。
—
2. Property Get/Let/Set の正しい使い分け
クラスモジュール内では、以下の3つの役割を厳格に使い分けます。
- Property Get: 値を「取得」する。読み取り専用にすることも容易。
- Property Let: プリミティブ型(String, Long, Double等)の値を「設定」する。
- Property Set: オブジェクト型(Worksheet, Collection, Dictionary等)の参照を「設定」する。
実践的なクラス設計例:`CUserRecord`
以下は、データの整合性を担保しつつ、外部連携を意識した設計のサンプルです。
‘ クラス名: CUserRecord
Option Explicit
‘ プライベート変数(外部から直接アクセスさせない)
Private pUserID As String
Private pTargetSheet As Worksheet
‘ [Get] 値を返すのみ(読み取り専用にしたい場合はLetを書かなければ良い)
Public Property Get UserID() As String
UserID = pUserID
End Property
‘ [Let] 値の代入時にバリデーションを組み込む
Public Property Let UserID(ByVal Value As String)
If Len(Value) <> 8 Then
Err.Raise vbObjectError + 1001, , “UserIDは8桁である必要があります。”
End If
pUserID = Value
End Property
‘ [Set] オブジェクトの参照をセットする(Setキーワードが必要)
Public Property Set TargetSheet(ByVal Value As Worksheet)
If Value Is Nothing Then
Err.Raise vbObjectError + 1002, , “シートが指定されていません。”
End If
Set pTargetSheet = Value
End Property
—
3. 現場で「死なない」ための3つの鉄則
① 「不正な状態」を許容しない
`Property Let` の中で、値が入ってきた瞬間にチェックを行ってください。後から「なぜこの値が入ったんだ?」と悩む時間をゼロにできます。
② データベース連携には「遅延初期化」を検討する
もしそのクラスが巨大なデータを扱う場合、インスタンス生成時に全てをロードするのは非効率です。`Property Get` が呼ばれたタイミングで初めてDBに接続する「遅延初期化(Lazy Initialization)」を設計に取り入れてください。
③ 継承がないVBAでの「インターフェース」の活用
VBAには強力な継承機能はありませんが、`Implements`によるインターフェース実装は可能です。複数のクラスに共通のメソッドを強制させたい場合、この設計手法が保守性を飛躍的に高めます。
—
4. プロダクションコードとしての呼び出し方
実際に利用する際のメインプロシージャです。エラーハンドリングとセットで運用することで、堅牢なツールが完成します。
Sub Main()
Dim user As New CUserRecord
On Error GoTo ErrorHandler
‘ ここでバリデーションが働き、8桁以外ならエラーを飛ばす
user.UserID = “A1234567”
‘ オブジェクトの代入は必ずSet
Set user.TargetSheet = ThisWorkbook.Sheets(“Data”)
MsgBox “設定完了: ” & user.UserID
Exit Sub
ErrorHandler:
MsgBox “エラー発生: ” & Err.Description, vbCritical
End Sub
—
最後に:なぜ「カプセル化」にこだわるのか
あなたが書いたコードを、半年後に別の担当者が触るかもしれません。その時、`Public変数`だらけのコードは「地雷原」ですが、`Property`で守られたクラスは「説明書付きの部品」です。
「変更に対して壊れにくいこと」こそが、VBAエンジニアにとっての最大の価値です。
変数を隠し、ロジックをクラスに閉じ込める。この一見面倒に見える一手間が、あなたの業務を自動化する最強の武器になります。さあ、今すぐコードの `Public` を書き換えることから始めましょう。
