2.3 委譲で継承を代用する

前章では、同じobject型の変数に別のクラスを代入すると、呼び出されるメソッドが各クラスで個別に定義されたメソッドになることを示しました。この性質を使うことで、オブジェクトの継承に必要な擬似的に実現することが出来ます。

具体的な方法に移りましょう。あるクラスclass1において、メソッドDoAction()を2種類の動的継承をするときを考えます。そのために必要な手順を示します:

  1. メソッドDoAction()を分離し、委譲するクラスsubclass1aとsubclass1b(以下、移譲先クラスとする)に実装する。
  2. class1に移譲先クラスを格納するobject型の変数aDelegateを追加する。
  3. class1の初期化時に、移譲先クラスをaDelegateにセットするプロシージャを標準モジュールにつくる。
  4. class1のメソッドDoActionでは、aDelegateのDoActionを呼び出す。

このようにすると、aDelegateにsubclass1aおよびsubclass1bを代入したとき、class1.DoAction()は各移譲先クラスのDoAction()になります。

以上の手順を実際のコードで見ていきましょう。まずは、class1の実装です:


[class1]
Dim aDelegate As Object

Public Sub Initialize(dele As Object)
    If Not dele Is Nothing Then
        Set aDelegate = dele
        aDelegate.Initialize Me
    End If
End Sub

Public Sub DoAction()
    aDelegate.DoAction
End Sub

変数aDelegateの扱いに注意して下さい。メソッドInitialize()では、移譲先オブジェクト変数deleに、自分自身の参照を与えています。これによって、class1にPublicなメソッドや変数を追加すれば、移譲先のクラスから参照が出来るようになります。

次に、委譲するクラスsubclass1a, subclass1bの実装です。


[subclass1a]
Dim parent As class1

Public Sub Initialize(cls1 As class1)
    Set parent = cls1
End Sub

Public Sub DoAction()
    MsgBox "class1a"
End Sub

[subclass1b]
Dim parent As class1

Public Sub Initialize(cls1 As class1)
    Set parent = cls1
End Sub

Public Sub DoAction()
    MsgBox "class1b"
End Sub

全く同じような実装になっていますが、継承がないので仕方ありません。実際は、DoAction()の中身のないクラス(Abstract Classに相当)を別に定義しておき、それをコピー&ペースとして使っています。

最後に、class1と移譲先クラスを結合させたclass1a, 1bを作成するメソッドです。標準モジュールで定義しておきます。


[module1]
Public Function GetClass1a() As class1
    Dim cls1 As New class1
    cls1.Initialize New class1a
    Set GetClass1a = cls1
End Function

Public Function GetClass1b() As class1
    Dim cls1 As New class1
    cls1.Initialize New class1b
    Set GetClass1a = cls1
End Function

これで準備は終了です。テストしてみましょう:


[test]
Sub Test()
    Dim cls1a As class1
    Dim cls1b As class1
    Set cls1a = GetClass1a()
    Set cls1b = GetClass1b()
    cls1a.DoAction
    cls1b.DoAction
End Sub

実行すると、順に「class1a」「class1b」と表示されます。これで継承もどきを作成することが出来ました。