Property LetとProperty Getを使い分けずに全部Publicの変数で済ませていた頃のコードを見返すと、正直かなり恥ずかしくなります。カプセル化の意味をJavaのクラス設計と対比させながら理解し直した記録です。
クラスモジュールの作り方
図1: クラスモジュールのProperty/Method/Eventの構成
VBEメニュー → 挿入 → クラスモジュール で追加できます。クラス名はプロパティウィンドウの (Name) で設定します。
Property Get / Let / Set
クラス内のプライベートフィールドを外部から読み書きするためのアクセサです。
' ── clsProduct.cls ──────────────────────────────────────
Option Explicit
' プライベートフィールド(外部から直接アクセス不可)
Private m_Id As Long
Private m_Name As String
Private m_Price As Long
' ── ID(読み取り専用)──
Public Property Get Id() As Long
Id = m_Id
End Property
' ── 名前(読み書き可・バリデーションあり)──
Public Property Get Name() As String
Name = m_Name
End Property
Public Property Let Name(ByVal v As String)
If Len(Trim(v)) = 0 Then Err.Raise 5, , "名前を空にできません"
m_Name = Trim(v)
End Property
' ── 価格(読み書き可・0以上チェック)──
Public Property Get Price() As Long
Price = m_Price
End Property
Public Property Let Price(ByVal v As Long)
If v < 0 Then Err.Raise 5, , "価格は0以上にしてください"
m_Price = v
End Property
' ── 初期化メソッド(コンストラクタ相当)──
Public Sub Init(ByVal id As Long, ByVal name As String, ByVal price As Long)
m_Id = id
Me.Name = name
Me.Price = price
End Sub
' ── 表示用文字列 ──
Public Function ToString() As String
ToString = "[" & m_Id & "] " & m_Name & " ¥" & m_Price
End Function
Initialize / Terminate
クラスモジュールにはオブジェクト生成・解放時の特殊イベントがあります。
' ── Class_Initialize(New 時に自動実行)──
Private Sub Class_Initialize()
m_Price = 0 ' デフォルト値設定
Debug.Print "clsProduct 生成"
End Sub
' ── Class_Terminate(Set Nothing / スコープ抜け時に自動実行)──
Private Sub Class_Terminate()
Debug.Print "clsProduct 解放"
End Sub
メソッドの定義
Public Sub / Public Function がそのままメソッドになります。
Javaクラスとの対比
| 機能 | Java | VBA クラスモジュール |
|---|---|---|
| クラス定義 | public class Product {} | クラスモジュール(.cls) |
| フィールド(非公開) | private int price; | Private m_Price As Long |
| ゲッター | getPrice() | Property Get Price() |
| セッター | setPrice(int v) | Property Let Price(v As Long) |
| コンストラクタ | public Product() | Class_Initialize + Init メソッド |
| デストラクタ | GC(finalizeは非推奨) | Class_Terminate |
| インスタンス生成 | new Product() | New clsProduct |
クラスのインスタンス化と使用
Option Explicit
Sub UseProductClass()
' インスタンス生成
Dim p As clsProduct
Set p = New clsProduct
' Init メソッドで初期化
p.Init 1, "ノートPC", 89800
' Property でアクセス
Debug.Print p.ToString ' → [1] ノートPC ¥89800
p.Price = 79800 ' Property Let 経由で設定
Debug.Print p.Price ' → 79800
' 解放
Set p = Nothing
End Sub
まとめ
VBAのクラスモジュールはJavaほど強力ではありませんが、Property によるカプセル化と Initialize/Terminate を使いこなすことで、保守しやすいコードを書くことができます。
✅ 次の章では…
PART 08 では 参照設定とバインディング を解説します。アーリー/レイトバインディングの使い分けと、配布時の注意点を紹介します。
VBAクラスモジュールでよくある誤り
クラスモジュールは強力ですが、VBA固有のオブジェクト管理を理解しないとメモリリークや予期しないエラーが発生します。
| 誤り/失敗パターン | 何が起きるか | 正しい対処/防止策 |
|---|---|---|
| Class_TerminateでリソースをNothingにしない | 参照が残り続け、オブジェクトが意図しないタイミングまで解放されずメモリを消費する | Class_Terminate内で保持しているオブジェクト変数をSet obj = Nothingで確実に解放する |
| Property LetとProperty Getのデータ型を一致させない | 型不一致エラーが発生し、プロパティへの代入・読み取りができなくなる | LetとGetで同じデータ型(As Integer等)を指定し、コンパイル時に型の整合性を確認する |
| 循環参照を作成する | 2つのクラスが互いを参照し合うとClass_Terminateが呼ばれず、オブジェクトが解放されない | 設計でクラス間の参照方向を一方向に保ち、循環参照が必要な場合はWeakRef相当のVariant型参照で代用する |