VBAはクラスを継承することができないが、インターフェースを作成することでポリモーフィズムを実現させることができる。
元ネタはこちらのサイト
VBAに関しては入門者向けの情報が多いなか、高度な情報を提供してくれる大変貴重なサイトである。
これを使って、何か役に立つコードが書けないか検証してみた。
できたのが、以下のコード群。
内容は、Word・Excel・テキストの3種類を統一的な方法で扱うというもの。
こちらがクラスモジュール(IDocument)のコード
Public DocumentPath As String Public Sub OpenItem() End Sub Public Function GetPages() End Function Public Function UnitOfPage() End Function
これがクラスモジュール(ExcelDocument)のコード
Implements IDocument Private DocumentPath As String Private file As Workbook Sub IDocument_OpenItem() Set file = Workbooks.Open(DocumentPath) End Sub Private Property Get IDocument_DocumentPath() As String IDocument_DocumentPath = DocumentPath End Property Private Property Let IDocument_DocumentPath(ByVal filepath As String) DocumentPath = filepath End Property Public Function IDocument_GetPages() IDocument_GetPages = file.Sheets.Count End Function Public Function IDocument_UnitOfPage() IDocument_UnitOfPage = "シート" End Function
これがクラスモジュール(WordDocument)のコード
Implements IDocument Private DocumentPath As String Private file As Object Sub IDocument_OpenItem() With CreateObject("Word.Application") Set file = .Documents.Open(DocumentPath) .Visible = True End With End Sub Private Property Get IDocument_DocumentPath() As String IDocument_DocumentPath = DocumentPath End Property Private Property Let IDocument_DocumentPath(ByVal filepath As String) DocumentPath = filepath End Property Public Function IDocument_GetPages() IDocument_GetPages = file.Range.Information(4) '引数の4は、WordVBAの定数「wdNumberOfPagesInDocument」の値 End Function Public Function IDocument_UnitOfPage() IDocument_UnitOfPage = "ページ" End Function
これがクラスモジュール(TextDocument)のコード
Implements IDocument Private DocumentPath As String Sub IDocument_OpenItem() Dim WSH Set WSH = CreateObject("Wscript.Shell") WSH.Run """" & DocumentPath & """", 3 Set WSH = Nothing End Sub Private Property Get IDocument_DocumentPath() As String IDocument_DocumentPath = DocumentPath End Property Private Property Let IDocument_DocumentPath(ByVal filepath As String) DocumentPath = filepath End Property Public Function IDocument_GetPages() IDocument_GetPages = 1 End Function Public Function IDocument_UnitOfPage() IDocument_UnitOfPage = "ファイル" End Function
これが標準モジュールに書いたテスト
Sub test() Dim x(1 To 3) As IDocument Set x(1) = New ExcelDocument x(1).DocumentPath = "C:\work\exceltest.xlsm" Set x(2) = New WordDocument x(2).DocumentPath = "C:\work\wordtest.docx" Set x(3) = New TextDocument x(3).DocumentPath = "C:\work\texttest.txt" For i = 1 To 3 x(i).OpenItem Debug.Print x(i).GetPages & x(i).UnitOfPage Next i End Sub
3種類の異なったファイルを、IDocument型の配列に入れて統一的に扱うことができる。
実行すると
4シート 2ページ 1ファイル
と表示された。
まぁでもインターフェースが無くてもObject型に代入してやれば、ポリモーフィズムができてしまうので、あまりありがたみは分からないかもしれない。
あえてインターフェースを使うメリットとしては、コードの信頼性が増すこと。
インターフェース型の変数を介した場合、メソッドが存在することをコンパイル段階で保証してくれるため、より堅牢なコードになる。また、具像クラスにのみ存在するメソッドは、インターフェース型の変数を介した場合はアクセスできなくなる。
今回のサンプルを改良すれば、特定フォルダに入っているすべてのファイルから文字列を検索したりできると思う。(ポリモーフィズムにより、テキストならそのまま検索・Officeファイルならオートシェイプ内のテキストもチェックするなど)