6
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Visual BasicAdvent Calendar 2023

Day 17

VBAでインターフェイス

Last updated at Posted at 2023-12-16

VBAでインターフェイス

自分はVBA歴が長い方だと思いますが、VBAでインターフェイスが使えることを最近知りました。それはもうビックリして、少し感動しました。
とは言え今すぐにこれを使って何かを作るなんてことはありそうもなく、とりあえず備忘録として、試したことをまとめておきたいと思います。

インターフェイスとは

インターフェイスとは、クラスや構造体が定義するプロパティやメソッドなどのシグネチャ(メソッドの引数や戻り値の型、メソッドの名前など)のみを書いたものです。プロパティやメソッドの識別のみが目的で実装は一切ありません。インターフェイスを実装するクラスはそのインターフェイスのすべてのメンバを実装しなければなりません。

クラスモジュールで作る

まずはインターフェイス用のクラスモジュールを追加します。名前はIAnimalとしました。
とりあえず一つ、メソッドのシグネチャを以下のように書きます。アクセス修飾子はリファレンスではPublicを書くと説明されていますが、必要ないでしょう。(VB.NETやC#に合わせて)

IAnimal.cls

Sub CallOut()
    
End Sub

簡単なんで、ついでにもう一つ別のインターフェイスも書いておきましょう。名前はIDebugとして、ここにもメソッドを一つ書きます。

IDebug.cls

Sub DebugPrint()
    
End Sub

次に、これら二つのインターフェイスを実装するためのCatクラスを作ります。Catクラス用のクラスモジュールを追加して、宣言セクションにImplementsキーワードに続けてインターフェイス名を書きます。

Cat.cls
Implements IAnimal
Implements IDebug

すると、オブジェクトボックスに2つのインターフェイスが現れます。

image.png

IAnimalインターフェイスを選択すると、

image.png

IAnimal_CallOutメソッドが出現します。

image.png

  • 全てのメンバが出現するわけではない(インターフェイスのクラスモジュールで一番上に書かれたものだけ)。
  • 全てのメンバを実装しないとエラーとなる(インターフェイスのメンバが複数の場合)。
  • 手書きで実装する場合、インターフェイス名とアンダースコアをメソッド名(またはプロパティ名)に付加する。
  • 出現したメンバのアクセス修飾子はPrivateがつく。
  • インターフェイス側にはアクセス修飾子をつけない(リファレンスではpublicを付けるとの説明があるが不要)。
  • 出現したメソッドをPublicにすればインスタンスで使用できるようになる。
  • その場合、利用時のメソッド名はCallOutではなくIAnimal_CallOutとなる。

以下にCatクラスの簡単な実装を書いてみました。

Cat.cls

' 実装するインターフェイスを設定する(複数のインターフェイスを設定可能)
Implements IAnimal
Implements IDebug

Private Const meow As String = "にゃー"

Public Sub Hoge()
    MsgBox "Hoge - 猫ほげ", vbInformation
End Sub

Private Sub IAnimal_CallOut()
    Debug.Print "CallOut - " & meow
End Sub

Private Sub IDebug_DebugPrint()
    Debug.Print "DebugPrint - わたしは猫です"
End Sub

ついでにDogクラスも書いてみました。

Dog.cls

Implements IAnimal
Implements IDebug

Private Const bowwow As String = "わんわん"

Public Sub Hoge()
    MsgBox "Hoge - 犬ほげ", vbInformation
End Sub

Private Sub IAnimal_CallOut()
    MsgBox "CallOut - " & bowwow, vbInformation
End Sub

Private Sub IDebug_DebugPrint()
    Debug.Print "DebugPrint - わいは犬や"
End Sub

2つのクラスを使ってみる

準備が整ったのでモジュールを追加してインターフェイスを実装したCatクラスとDogクラスを使ってみます。

Module1.bas

Sub x()

    ' 2つのクラスとコレクションの生成
    Dim AnimalBox As New Collection
    Dim neko As New Cat: AnimalBox.Add neko
    Dim inu  As New Dog: AnimalBox.Add inu

'    Dim hg As IAnimal
'    For Each hg In AnimalBox
'        hg.Hoge
'    Next
    
    Dim pet As IAnimal
    For Each pet In AnimalBox
        pet.CallOut
    Next
    
    Dim dbg As IDebug
    For Each dbg In AnimalBox
        dbg.DebugPrint
    Next
    
End Sub

まずは、二つのクラスのインスタンスをコレクションに追加します。
その下のコメントアウトしたFor Eachは、二つのクラスに敢えて同名でHogeメソッドを書き、ループ内で実行させてみたテストの痕跡です。
これを動作させるとどうなるか:question:列挙されるアイテムを受けるhg変数はIAnimal型ですが、これはエラーとなり実行できません。

image.png

続く二つのループではIAnimalインターフェイスのメンバを実装したCallOutメソッドと、IDebugインターフェイスのメンバを実装したDebugPrintメソッドを実行させています。
そして、これは問題なく実行されます:bangbang:
コレクション内のnekoinuは別々のクラスのインスタンスですが、同じ構文でメソッドを実行できています。正にここがキモ、ポリモーフィズムってやつですね:laughing:

CatクラスのCallOutではDebug.Printで「にゃー」と鳴かせていますが、DogクラスのCallOutではDebug.PrintではなくMsgBoxで鳴かせています。この様に同じCallOutでも全く違った挙動をさせることができます。

この他にもインターフェイスの効用として疎結合(クラスの変更容易性)やクラスの特性・動作をユーザーに約束する機能保証などがあります。

以下、インターフェイスについての良い説明記事がありました。

残念ながらIAnimal型のインスタンスでCatクラス(及びDogクラス)のHogeメソッドは呼び出せません。これはVB.NETであればキャストして呼び出せます。

Program.vb

Dim pet As IAnimal = New Cat

DirectCast(pet, Cat).Hoge()

さいごに独り言

今年は業務ツールを作る際、意識的にVB.NETを避けてC#で書いていましたが、この記事の検証のために久々にVB.NETに触れ、何とも懐かしくて胸躍りました。

やっぱりVBはええなあ、、、

:santa_tone1::christmas_tree::santa_tone1::christmas_tree::santa_tone1::christmas_tree:

6
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?