たにぐちBLOG

C#が好きでたまんない

  PASSJブログ :: ホーム :: 連絡をする :: RSS  :: ATOM :: Login
  31 投稿数 :: 0 ストーリー :: 56 コメント :: 10 トラックバック

過去の記事

カテゴリ

イメージギャラリ

よく知られている通り、Visual Basic 6.0ではクラスの継承ができません。よって、抽象クラスもないしprotectedというアクセス指定子もありません。VB6プログラマにとって唯一インターフェース継承のみが残されていますが、これも機能は貧弱です。それではVB6プログラマはデザインパターンを意識したプログラミングはあきらめなければならないのでしょうか?
今回は、VB6のインターフェース継承の機能が貧弱であることを逆に利用してVB6で擬似的に抽象クラスを実装してしまおうというお話です。

インターフェースには本来実装が許されません。しかし、VB6では幸いにも?それができてしまいます。
以下のようなクラスを作成してみました。


' 擬似抽象クラス
' PseudoAbstractClass.cls(クラスモジュール)

Private m_SubClass As PseudoAbstractClass

' 内部変数(本当はprotectedにしたい)
Private m_Message As String
Private m_Count As Integer

' 子クラスを保持します
Public Property Set SubClass(value As PseudoAbstractClass)
   Set m_SubClass = value
End Property

Public Sub Release()
   ' 後始末用
   ' ここでは実装しない
End Sub

Public Property Get Message() As String
   Message = m_Message
End Property

Public Property Let Message(value As String)
   m_Message = value
End Property

Public Property Get Count() As Integer
   Count = m_Count
End Property

Public Property Let Count(value As Integer)
   m_Count = value
End Property

' 擬似abstract関数。子クラスで実装
Public Function SuperClassAbstractFunction() As String
   SuperClassAbstractFunction = _
      m_SubClass.SuperClassAbstractFunction
End Function

Public Sub SuperClassAbstractSub()
   m_SubClass.SuperClassAbstractSub
End Sub

Public Sub SuperClassSub()
   Dim I As Integer
   For I = 1 To m_Count
      Debug.Print SuperClassAbstractFunction
   Next I
   Call SuperClassAbstractSub
End Sub


Visual Basic 6.0ではprotectedアクセス指定子がないので、仕方なくプロパティで代用します。メンバ変数はMessageと、Countです。
もう一つ、m_SubClassという変数があります。プロパティSubClassで取得した子クラスはここに格納されます。擬似抽象メソッドSuperClassAbstractFunction、SuperClassAbstractSubでは、m_SubClassの相当関数を実行します。擬似抽象メソッドは、これを継承したクラスが決定後初めて決まります。今は入れ物だけです。

メソッドSuperClassSubですが、ここでは抽象メソッドを使用して何を実行するかが書かれています。ここでは、SuperClassAbstractFunctionの戻り値をm_Count回デバッグウィンドウに表示した後、SuperClassAbstractSubを実行するといった単純なものです。擬似抽象クラスSuperClassAbstractFunctionと、SuperClassAbstractSubが何を行うかまだ決定していないことにご注意ください。

早速、この擬似抽象クラスを継承した子クラスを作成します。


' 子クラス
' SubClass1.cls(クラスモジュール)

Implements PseudoAbstractClass

Private m_BaseClass As PseudoAbstractClass

Private Sub Class_Initialize()
    ' 擬似抽象クラスのインスタンスを作り、そのSubClassプロパティに自分を代入する。
   Set m_BaseClass = New PseudoAbstractClass
   Set m_BaseClass.SubClass = Me
End Sub

Private Sub PseudoAbstractClass_Release()
   ' 後始末。使用後、必ず実行する。
   Set m_BaseClass.SubClass = Nothing
   Set m_BaseClass = Nothing
End Sub

Private Property Set PseudoAbstractClass_SubClass(value As PseudoAbstractClass)
   ' 実装しない
End Property

Private Property Let PseudoAbstractClass_Message(value As String)
   m_BaseClass.Message = value
End Property
Private Property Get PseudoAbstractClass_Message() As String
   PseudoAbstractClass_Message = m_BaseClass.Message
End Property
Private Property Let PseudoAbstractClass_Count(value As Integer)
   m_BaseClass.Count = value
End Property
Private Property Get PseudoAbstractClass_Count() As Integer
   PseudoAbstractClass_Count = m_BaseClass.Count
End Property

Private Sub PseudoAbstractClass_SuperClassSub()
   m_BaseClass.SuperClassSub
End Sub

' ここより上は全て共通
' この下よりこのクラスの固有の実装(override)

Private Function PseudoAbstractClass_SuperClassAbstractFunction() As String
   PseudoAbstractClass_SuperClassAbstractFunction = "*****" & m_BaseClass.Message & "*****"
End Function

Private Sub PseudoAbstractClass_SuperClassAbstractSub()
   Debug.Print "******************************" & vbCrLf
   Debug.Print "*********" & m_BaseClass.Message & "*********" & vbCrLf
   Debug.Print "******************************" & vbCrLf
End Sub


冒頭にImplements PseudoAbstractClassとあります。これで、このクラスのオブジェクトをPseudoAbstractClassのSubClassプロパティに入れることができるようになります。このクラスのInitializeメソッド(コンストラクタ)で、擬似抽象クラスのインスタンスを作り、SubClassプロパティに自分(Me)を代入してしまいます。Message, Countプロパティはそのまま親クラスのものを引き継ぎます。PseudoAbstractClass_SuperClassSubは親クラスのものをそのまま引き継ぐため、m_BaseClassの相当関数を実行します。ここより上は全て共通です。PseudoAbstractClass_SuperClassAbstractFunction、PseudoAbstractClass_SuperClassAbstractSubで、このクラスに固有の実装(override)をします。メッセージに「*」の飾りをつけるだけという簡単なものです。

「ここより上は全て共通」コメントより上の部分をコピーして、SubClass2.clsというクラスを作り貼り付けます。その下に以下のような関数を作成します。


Private Function PseudoAbstractClass_SuperClassAbstractFunction() As String
   PseudoAbstractClass_SuperClassAbstractFunction = "-----" & m_BaseClass.Message & "-----"
End Function

Private Sub PseudoAbstractClass_SuperClassAbstractSub()
   Debug.Print "------------------------------" & vbCrLf
   Debug.Print "---------" & m_BaseClass.Message & "---------" & vbCrLf
   Debug.Print "------------------------------" & vbCrLf
End Sub


「*」が「-」に変わっただけです(^^;。以下は使用例です。


' Form1.frm(フォームモジュール)

Private Sub Command1_Click()
   Dim AbstractBaseClass1 As PseudoAbstractClass
   Set AbstractBaseClass1 = New SubClass1
   AbstractBaseClass1.Message = "継承クラス1"
   AbstractBaseClass1.Count = 2
   AbstractBaseClass1.SuperClassSub
   ' 後始末は必ず実行する
   AbstractBaseClass1.Release
   Dim AbstractBaseClass2 As PseudoAbstractClass
   Set AbstractBaseClass2 = New SubClass2
   AbstractBaseClass2.Message = "継承クラス2"
   AbstractBaseClass2.Count = 3
   AbstractBaseClass2.SuperClassSub
   AbstractBaseClass2.Release
End Sub


出力は以下の通りです。


*****継承クラス1*****
*****継承クラス1*****
******************************

*********継承クラス1*********

******************************

-----継承クラス2-----
-----継承クラス2-----
-----継承クラス2-----
------------------------------

---------継承クラス2---------

------------------------------



一見、子クラスのメンテが大変のように見えますが、擬似抽象メソッドの実装を除きほとんど共通ですので、一個作成、変更すれば後はコピペでいけます。
基本的な考え方は、親クラスで入れ物を用意しておき、子クラスで入れ物に実装することです。新しい実装がほしくなれば、SubClass1をじゃんじゃんコピーして擬似抽象メソッドの中だけ書き換えればよいわけです。

VBのInterfaceは、一回継承したものを親クラスとしてさらに継承することはできません。その代わり、一度に複数のInterfaceを継承することができます。

この考え方でVB6で色々なデザインパターンを試してみると面白そうです。できないもの、複雑すぎて実用性のないものも出てくるとは思いますが、「継承」について基本に戻って考えさせてくれる良い機会になるかもしれません。

投稿日時 : 2005年8月13日 4:45

コメントを追加

# re: VB6.0 でポリモーフィズム (多態性) 2007/04/21 16:51 じゃんぬねっと日誌
re: VB6.0 でポリモーフィズム (多態性)

コメント

タイトル:
名前:
Url:
コメント: