なんでVBAでクラスモジュールを使うのか
なんでVBAでクラスモジュールを使うのか
基本的には標準モジュールで十分
プログラムを書くときに、モノとして扱った方が楽な場合がある。
モノの機能だけが欲しいのなら、標準モジュールでいい。
機能のまとまりを表す名前を付けて、その中にメソッドをまとめておくのである。
たとえば、ユーザに選ばせたフォルダのフォルダパスを取得するという処理がある。
FileDialog
オブジェクトを使う処理だが、毎回いちいちFileDialog
オブジェクトを取得してフォルダパスを返す処理を書くのはめんどくさい。 だから、FileDialog
オブジェクトをラップしたメソッドを書く。
Option Explicit Private m_FSO As Object Public Function GetSelectedFolderPath( _ Optional ByVal a_DefaultDir As String, _ Optional ByVal a_Title As String) As String If m_FSO Is Nothing Then Set m_FSO = CreateObject("Scripting.FileSystemObject") Dim ret As String ret = "" '第1引数省略なら最初に表示するディレクトリをこのブックのある' 'ディレクトリにする ' If a_DefaultDir = "" Then _ a_DefaultDir = ThisWorkbook.Path If Not m_FSO.FolderExists(a_DefaultDir) Then _ a_DefaultDir = ThisWorkbook.Path Dim folderPath As String Dim isSelected As Boolean Dim folderPicker As FileDialog Set folderPicker = Application.FileDialog(msoFileDialogFolderPicker) With folderPicker .InitialFileName = a_DefaultDir If a_Title <> "" Then .Title = a_Title Else .Title = "フォルダ選択" End If isSelected = .Show If isSelected Then ret = .SelectedItems(1) Else ret = "" End If End With GetSelectedFolderPath = ret End Function
このように、たとえばFileDialogUtil
という標準モジュールに、GetSelectedFolderPath
というメソッドを作っておくと、あとは、
Dim rootDir As String rootDir = FileDialogUtil.GetSelectedFolderPath
というコードを書くだけで、〝ユーザが選択したフォルダのフルパスを取得する〟という処理が書けるようになる。
この調子で、FileDialog
オブジェクトを利用する処理を、標準モジュールFileDialogUtil
にまとめておくと、以後プログラムを書くのが非常に楽になる。
このように、FileDialog
というモノが使いたい場合でも、機能が欲しいだけなら標準モジュールで十分である。
〝運用でカバー〟的にはなるが、〝メソッド呼び出し時には、必ずモジュール名を記述する〟というルールで用いれば、〝静的クラス〟のような使い方ができる。
クラスモジュールを使いたくなるとき
では、どういうときにクラスモジュールを使いたくなるか。
上記FileDialogUtil
では、モノ自体、つまり利用しようとするFileDialog
オブジェクト自体には〝個性〟はなくてもよかった。
利用するFileDialog
は、いついかなるときでも〝タダのFileDialog
オブジェクト〟なのであって、色も味も身長も体重も、一切の特徴がない〝タダのFileDialog
オブジェクト〟である。
それに対して次のような場合はどうか。
このような場合である。
「〝ある〟テキストファイル」なので、そのモノには個性がある。
〝その〟テキストファイルのファイルパスであったり、〝その〟テキストファイルの内容(要するにテキストデータ)であったり、トータルの行数であったり。
だいたい、プログラムの中でテキストファイルを扱いたいという場合、〝テキストファイルの機能〟を使いたい、という場合はないと思う。(そんな状況は、想像できない。)
このような場面のはずである。
そうすると、たとえば、
があったら、非常に便利なはずである。
しかしながら、デフォルトではそのように振る舞ってくれる便利なオブジェクトは存在しない。
このようなときにクラスモジュールを使いたくなる。
上記の例でいえば、
を自作するのである。
標準モジュールにメソッドを書いて上記の処理を実現しようと思ったら、必要になるその都度、そのメソッドに当該テキストファイルのフルパスを渡す必要がある。(テキストファイルをテキストファイルというモノとして変数に入れて保持する方法がないのだから、当たり前である。)テキストファイルを開き、読み込んだり書き込んだりする処理自体はまとめておくことができるものの、この〝テキストファイルのフルパスを渡す〟という手順自体は(基本的に)飛ばすことができない。
たとえば、テキストファイルのフルパスと行番号を渡して、当該テキストファイルの当該行のテキストを取得するGetTextData(FilePath As String, LineNumber As Long)
というメソッドがあったとする。
そうして、たとえば変数tmp
に、そのテキストファイルの3行目と5行目のテキストを結合して代入したい場合、次のようなコードを書くことになる。
Dim tmp As String tmp = GetTextData("X:\hoge\hoge.txt", 3) & GetTextData("X:\hoge\hoge.txt", 5)
これは非常にめんどくさい上、直感的でない。〝テキストファイルそのもの〟を指し示すオブジェクトが(基本的には)ないので、毎度毎度当該テキストファイルのフルパスを指定することになる。(もちろん、Scripting.TextStreamオブジェクトを使うとか、一旦読み込んだテキストファイルの内容を配列に入れてしまうとか、方法はある。)
その点、たとえば、次のような機能を持ったEasyTextFile
というクラスがあったとする。
Path
プロパティは、そのテキストファイルのフルパスを表す。Item(LineNumber)
メソッドは、指定した行(引数LineNumber
)にあるテキストデータを返す。
そうすると、上記「変数tmp
に、そのテキストファイルの3
行目と5
行目のテキストを結合して代入」するという処理は、次のようなコードで書ける。
Dim etf As New EasyTextFile etf.Path = "X:\hoge\hoge.txt" Dim tmp = String tmp = etf.Item(3) & etf.Item(5)
処理の例が単純なので、有難味を感じにくいかも知れないが、ここで用いた「hoge.txt
」のデータをプログラム内で参照する回数が増えるほど、恩恵を感じやすくなるはずである。 特に、一つのプログラム内で複数種類のテキストファイルを取り扱わなければならない場合に、より一層便利に感じるはずである。 たとえば、メールを自動で作成するプログラムで、
- 宛名人に関するデータをRecipient.txtから
- 差出人に関するデータをSender.txtから
- 本文に関するデータをMailBody.txtから
それぞれ取り出して使うとする。
上記クラスモジュールEasyTextFile
を用いるなら、たとえば、それぞれ
recipientData
senderData
bodyData
のように、役割明示的な変数名を付けてインスタンス化すれば、かなりコードの可読性が上がるはずである。
結論
〝個性のあるモノ〟をプログラム内で扱いたいときに、クラスモジュールを使いたくなる。
おわりに
素人の感想です。