前項で書いたように、目的は機能を共通部と固有部に分割することにより、再利用可能なフレームワークを作成することです。そこで、Decoratorの機能の分離するにはどうしたらよいのか考えてみましょう。
BookDecoratorの機能には、以下の2つに分けられます:
このうち、ブックのイベントをフックする部分は共通ですが、イベントの中身自体はそれぞれのブックで固有です。また、シートのDecoratorは必ず設定しますが、どのようなDecoratorを設定するかは異なるかもしれません。これらの前提に基づいて、共通部分をBookDecorator、固有部分を別クラスのBookDelegateに分離して実装すれば、所期の目的が達成されることになります。
では、いつもの如しでBookDecoratorとBookDelegateの実装全体を示して、それから各所を説明していきます。
[BookDecorator]
Public WithEvents wbook As Workbook
Public parent As AppDecorator
Private bookDele As Object
Private sheetDecorators As New Collection 'of SheetDecorator
Public Sub Initialize(wb As Workbook, d As Object, ad As AppDecorator)
Set wbook = wb
Set parent = ad
Set bookDele = d
If Not bookDele Is Nothing Then
bookDele.Initialize Me
bookDele.SetSheetDecorators
End If
Dim sd As SheetDecorator
End Sub
Public Sub AddSheetDecorator(sd As SheetDecorator)
sheetDecorators.Add Item:=sd
End Sub
[BookDelegate]
Public WithEvents wbook As Workbook
Public parent As BookDecorator
Public Sub Initialize(bd As BookDecorator)
Set wbook = bd.wbook
Set parent = bd
End Sub
Public Sub SetSheetDecorators()
End Sub
|
それでは部分ごとに見ていきます。まずはBookDecoratorの実装です。
Public WithEvents wbook As Workbook Public parent As AppDecorator Private bookDele As Object Private sheetDecorators As New Collection 'of SheetDecorator |
メンバ変数は前章で扱ったBookDecoratorに、移譲先のクラスを保持するbookDeleを追加してあります。委譲を実現するため、2章のようにObject型で受けています。
Public Sub Initialize(wb As Workbook, d As Object, ad As AppDecorator)
Set wbook = wb
Set parent = ad
Set bookDele = d
If Not bookDele Is Nothing Then
bookDele.Initialize Me
bookDele.SetSheetDecorators
End If
Dim sd As SheetDecorator
End Sub
|
初期化メソッドです。前章と違うのは、If Not bookDele〜の部分ですね。まず自分自身を引数にしてBookDelegate.Initializeを呼び出し、BookDecoratorとBookDelegateを関係づけます。そのあと、委譲されたSheetDecoratorを設定するメソッド(BookDelegate.SetSheetDecorators)を呼び出しています。
Public Sub AddSheetDecorator(sd As SheetDecorator)
sheetDecorators.Add Item:=sd
End Sub
|
SheetDecoratorの保持自体はBookDecoratorが行いますが、SheetDecoratorの取得はBookDelegateに委譲されています。したがって、BookDelegateは、自信が作成したSheetDecoratorを、BookDecoratorのsheetDecoratorsコレクションに放り込まなければなりません。そこで、AddSheetDecoratorメソッドを呼び出すことで、明示的にsheetDecoratorsコレクションを操作するようにしてあります。
では、移譲先のBookDelegateです。
Public WithEvents wbook As Workbook Public parent As BookDecorator |
BookDelegateでは、各マクロに固有なイベントを扱います。そのために、BookDecoratorと同様、Workbookのイベントをフックする変数wbookを持ちます。
Public Sub Initialize(bd As BookDecorator)
Set wbook = bd.wbook
Set parent = bd
End Sub
Public Sub SetSheetDecorators()
End Sub
|
初期化部分は、フック先のブックと親に当たるBookDecoratorとの関係付けですので見たままかと思います。そして、SetSheetDecoratorsメソッドに、SheetDecoratorを設定する処理を書くことになります。メソッドの中身は使用するブックにあうように書きます。
では、SetSheetDecoratorsメソッドの例を考えます。SheetDecoratorも、BookDecoratorと同様にSheetDelegateに独自部分を分離することができます。そうすると、SheetDecoratorとSheetDelegateを擬似継承したクラスを組み合わせる処理が必要です。そこで、ワークシート1のSheetDecoratorを、ある移譲先クラスConcreteSheetDelegateを関係づけて初期化するメソッドはこんな風になります:
Public Sub SetSheetDecorators()
parent.AddSheetDecorator CreateConcreteSheetDecorator(wbook.Worksheets(1))
End Sub
Public Function CreateConcreteSheetDecorator(ws As Worksheet) As SheetDecorator
Dim sdeco As New SheetDecorator
Dim sdele As New ConcreteSheetDelegate
sdeco.Initialize ws, sdele, parent
Set CreateConcreteSheetDecorator = sdeco
End Function
|
CreateConcreteSheetDecoratorは、ある組み合わせを作成するFactory Methodにあたります。SetSheetDecoratorsメソッドは、このメソッドによって確保されたSheetDecoratorをBookDecoratorに渡しているだけです。
そうそう、SheetDecoratorの実装を示さないと、「sdeco.Initialize〜」の部分がチンプンカンプンですね。SheetDecoratorとSheetDelegateの実装を示しておきます。話は子に当たるDecoratorがない分BookDecoratorより単純です。
[SheetDecorator]
Public WithEvents wsheet As Worksheet
Public parent As BookDecorator
Private sheetDele As Object
Public Sub Initialize(ws As Worksheet, d As Object, bd As BookDecorator)
Set wsheet = ws
Set parent = bd
Set sheetDele = d
If Not sheetDele Is Nothing Then
sheetDele.Initialize Me
End If
End Sub
[SheetDelegate]
Public WithEvents wsheet As Worksheet
Public parent As SheetDecorator
Public Sub Initialize(sd As SheetDecorator)
Set wsheet = sd.wsheet
Set parent = sd
End Sub
|