愚者の経験

「また今度」はほとんどこない

VBAの擬似継承

Implementsは「親クラスの実装をすべて書く」というのが最大のネックです。
プロパティ「Value1」「Value2」の値を足したり引いたりするだけでも
Implementsした場合は「親クラス_Value1」と「親クラス_Value2」のプロパティの定義が必須です。

違いだけ記述しつつ、多態性を利用するにはどうすればいいか考えました。

最終的にどうなるかというと
・親クラスと対になる操作クラス(自分で命名)を定義
・操作クラスは親クラスのインスタンスを持つ(変数名「This」とする)
・子クラスは親クラスをImplementsして、操作クラスのインスタンスを持つ(変数名「Base」とする)
・操作クラスの親クラスのインスタンス(This)に子クラスを代入する(ImplementsしているのでOK)
・親クラスには多態性を利用したいものだけを定義
・操作クラスでは多態性を利用しないプロパティ等を定義
・操作クラス内のメソッド内では親クラス(This)のメソッドを呼ぶ(→子クラス定義のメソッド)

操作クラスの「This」と子クラスの「Base」を隠蔽するために

操作クラスは「IOperator」クラス
子クラスは「IDerivator」クラス

をそれぞれImplemensするものとしました。

「IOperator」クラス

Option Explicit

Public Property Get Base() As Object
End Property

「 IDerivator」クラス

Option Explicit

Public Property Set This(SubClass As Object)
End Property

「c_Interface」クラス(親クラス)

Option Explicit

‘インターフェイスクラス(多態性の必要なプロシージャのみ)
Public Function Method0()
End Function

「c_Interface_op」クラス(操作クラス)

Option Explicit

Implements IOperator

Public Value1 As Integer
Public Value2 As Integer

Private This As c_Interface

Private Sub Class_Terminate()
    Set This = Nothing
End Sub

‘親クラスのメソッドと呼ぶ

Public Function Method0()
    This.Method0
End Function

Private Property Set IOperator_This(RHS As Object)
    Set This = RHS
End Property

「c_Minus」クラス(子クラス2)

Option Explicit

Implements c_Interface
Implements IDerivator

Private Base As c_Interface_op

Private Function c_Interface_Method0() As Variant
    MsgBox Base.Value1 – Base.Value2
End Function

Private Sub Class_Initialize()
    Set Base = New c_Interface_op
End Sub

Private Sub Class_Terminate()
    Set Base = Nothing
End Sub

Private Property Get IDerivator_Base() As Object
    Set IDerivator_Base = Base
End Property

「c_Plus」クラス(子クラス2)

Option Explicit

Implements c_Interface
Implements IDerivator

Private Base As c_Interface_op

Private Function c_Interface_Method0() As Variant
    MsgBox Base.Value1 + Base.Value2
End Function

Private Sub Class_Initialize()
    Set Base = New c_Interface_op
End Sub

Private Sub Class_Terminate()
    Set Base = Nothing
End Sub

Private Property Get IDerivator_Base() As Object
    Set IDerivator_Base = Base
End Property

標準モジュールとテストプロシージャ

Option Explicit

Public Function Instancing(SubClass As IDerivator) As IOperator
    Set Instancing = SubClass.Base
    Set Instancing.This = SubClass
End Function

Public Function test()
    Dim op As c_Interface_op
 
    ‘切り替えOK
    Set op = Instancing(New c_Minus)
    ‘Set op = Instancing(New c_Plus)
 
    op.Value1 = 20
    op.Value2 = 10
    op.Method0
 
End Function

たった2つのクラスのために4つのクラスを追加していますので結構アレかもしれませんが
同じプロパティを何度も書く必要はなくなりました。

共通のプロパティに対しては子クラスから「Base.」で参照できます。

しかし子クラス独自のメソッドを呼ぶ場合にはやはりキャストが必要になります。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。