2006 年 5 月 9 日 19 時 51 分

PuzzleSheetLoader: インタフェースの実装


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


IPuzzleLoader のインタフェースは作成したので、
それを実装したクラスを作成しよう。

まず必要となるのは、セル範囲から問題を読み出すクラスだ。
PuzzleSheetLoader とでも名前をつけよう。
このクラスには IPuzzleLoader を実装する。

わざわざ IPuzzleLoader インタフェースを定義したのは、
ファイルなどから問題を読み出すクラスを
後から容易に作成することができるように考えたからだ。

では、PuzzleSheetLoader について考えてみよう。
ワークシートから読み出すので、
PuzzleSheetLoader インスタンスを作成するときに、
セル範囲を表す Range オブジェクトを受け取ると良い。

通常ならば、コンストラクタとして設計するのだが、
VBA にはコンストラクタが存在しない。
クラス初期化ルーチンはあるが、
コンストラクタのように引数を受け取ることはできない。

コンストラクタはクラスごとにシグネチャが異なるので、
初期化用インタフェースとかを作ることもできない。
仕方ないので、初期化用のメソッドを作成して、
インスタンス作成後すぐにそれを呼び出す規則にしよう。

    Public Sub Construct(ByVal AnswerRange As Range)
    End Sub

呼び出しはこんな感じだ。仕方ない。

    Dim oLoader As PuzzleSheetLoader
    Set oLoader = New PuzzleSheetLoader
    Call oLoader.Construct(セル範囲)

後は、IPuzzleLoader を実装することだ。

VBA でインタフェースの実装をするためには、
Implements ステートメントを使う。
書くのは宣言セクション(Declarations)だ。

    Implements IPuzzleLoader

これを書くことにより、PuzzleSheetLoader は、
IPuzzleLoader 型として扱うことができるようになる。
インタフェースは実装を提供しないので、
IPuzzleLoader のメソッドに対応するコードは
PuzzleSheetLoader に書く必要がある。

メソッドの枠組みは、VBA の IDE が作ってくれる。
オブジェクトボックスに(エディタの左上 General って奴)
IPuzzleLoader を選択すると、プロパティ Answer の
実装のスケルトンが自動的に作成されたはずだ。

    Private Property Get IPuzzleLoader_Answer() As ArrayList
    End Property

同じように、プロシージャボックス(同右)から、
プロシージャを選択して、全てのスケルトンを作る。

    Private Property Get IPuzzleLoader_Width() As Long
    End Property

    Private Property Get IPuzzleLoader_Height() As Long
    End Property

    Private Property Get IPuzzleLoader_RowHints(ByVal Index As Long) As ArrayList
    End Property

    Private Property Get IPuzzleLoader_ColumnHints(ByVal Index As Long) As ArrayList
    End Property

このように、インタフェースを実装した場合、
インタフェース名_プロシージャ名 という名前になる。
これは、イベントプロシージャにも似ている。

気になる点は、実装メソッドが「Private」であることだ。

VBA のインタフェース実装は、
C# や Java のインタフェース実装とは少し異なり、
インタフェースの実装として定義したプロシージャは、
実装したクラスの Public プロシージャとはならない。

つまり、PuzzleSheetLoader 型のインスタンスから、
IPuzzleLoader のプロシージャを直接呼び出せないのだ。

    Dim oLoader As PuzzleSheetLoader
    Set oLoader = New PuzzleSheetLoader
    Call oLoader.Construct(セル範囲)
    Debug.Print oLoader.Width ' エラー

Width を呼ぶには、IPuzzleLoader 型に入れる必要がある。

    Dim oLoader As PuzzleSheetLoader
    Dim iLoader As IPuzzleLoader
    Set oLoader = New PuzzleSheetLoader
    Call oLoader.Construct(セル範囲)
    Set iLoader = oLoader
    Debug.Print iLoader.Width ' OK

COM のインタフェースポインタの取り扱いによる仕様だが、
これでは使う側のコーディングが面倒になる。
そこで C# や Java の実装のような仕掛けをしよう。

IPuzzleLoader のプロシージャを直接呼び出せないであれば、
全く同じプロシージャを全て定義してしまえばいいのだ。

    Public Property Get Width() As Long
    End Property

    Public Property Get Height() As Long
    End Property

    Public Property Get RowHints(ByVal Index As Long) As ArrayList
    End Property

    Public Property Get ColumnHints(ByVal Index As Long) As ArrayList
    End Property

    Public Property Get Answer() As ArrayList
    End Property

コードの実装はこちらに書く。
そして、インタフェースの実装は、
上記のコードを呼び出すだけとする。

    Private Property Get IPuzzleLoader_Width() As Long
        IPuzzleLoader_Width = Width
    End Property

    Private Property Get IPuzzleLoader_Height() As Long
        IPuzzleLoader_Height = Height
    End Property

    Private Property Get IPuzzleLoader_RowHints(ByVal Index As Long) As ArrayList
        Set IPuzzleLoader_RowHints = RowHints(Index)
    End Property

    Private Property Get IPuzzleLoader_ColumnHints(ByVal Index As Long) As ArrayList
        Set IPuzzleLoader_ColumnHints = ColumnHints(Index)
    End Property

    Private Property Get IPuzzleLoader_Answer() As ArrayList
        Set IPuzzleLoader_Answer = Answer
    End Property

こうすることにより、

PuzzleSheetLoader 型からもメソッドを呼び出す事ができる。
IPuzzleLoader の実装コードは、
PuzzleSheetLoader のメンバを呼び出すだけの役割だが、
IPuzzleLoader 型から呼び出された場合に必要だ。

よし、枠組みは整った。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.