VBScriptで学ぶデザインパターン入門:効率的なコード設計法

プログラミングにおいて、コードの設計は非常に重要です。

効率的で保守しやすいコードを書くために、多くのエンジニアが「デザインパターン」を利用しています。

デザインパターンとは、よくあるソフトウェア設計の問題に対する、再利用可能な解決策のことです。

本記事では、VBScriptという古典的なスクリプト言語を使いながら、デザインパターンの基本的な考え方を学び、実際に適用する方法を解説します。

デザインパターンとは?

デザインパターンとは、特定の課題に対して最適な解決策を提供するテンプレートです。

これを用いることで、開発者は以下の利点を得ることができます:

  • コードの再利用性の向上
  • 保守性の向上
  • 開発時間の短縮

デザインパターンは大きく3つに分類されます:

  • 生成パターン:オブジェクトの生成に関するパターン(例:シングルトン、ファクトリーパターン)
  • 構造パターン:オブジェクトの構造を整理するためのパターン(例:デコレータ、アダプタパターン)
  • 振る舞いパターン:オブジェクト間の連携や責任の分担を整理するパターン(例:オブザーバー、コマンドパターン)

VBScriptとデザインパターンの相性

VBScriptは、特にウェブブラウザや簡単な自動化スクリプトで利用される軽量スクリプト言語ですが、オブジェクト指向の考え方をサポートしており、デザインパターンを実装することも可能です。

VBScriptは、クラスの概念こそ持たないものの、関数プロシージャオブジェクトの仕組みを利用することで多くのデザインパターンを適用できます。


VBScriptでのデザインパターンの実装方法

シングルトンパターン

シングルトンパターンは、特定のクラスが一つのインスタンスしか持たないことを保証します。

VBScriptでは、クラス内でインスタンスを管理することでシングルトンを実現できます。

Class Singleton
    Private SharedInstance
    
    Private Sub Class_Initialize()
        ' 初期化処理
    End Sub
    
    Public Function GetInstance()
        If IsEmpty(SharedInstance) Then
            Set SharedInstance = New Singleton
        End If
        Set GetInstance = SharedInstance
    End Function
End Class

' シングルトンの使用例
Dim obj
Set obj = Singleton.GetInstance()

このコードでは、GetInstanceメソッドがインスタンスを一度だけ生成し、それ以降は同じインスタンスを返します。

ファクトリーパターン

ファクトリーパターンでは、オブジェクトの生成を専用のメソッドに委任することで、依存性を減らし、柔軟な拡張を可能にします。

Class AnimalFactory
    Public Function CreateAnimal(animalType)
        Select Case animalType
            Case "Dog"
                Set CreateAnimal = New Dog
            Case "Cat"
                Set CreateAnimal = New Cat
            Case Else
                Set CreateAnimal = Nothing
        End Select
    End Function
End Class

Class Dog
    Public Sub Speak()
        MsgBox "Woof!"
    End Sub
End Class

Class Cat
    Public Sub Speak()
        MsgBox "Meow!"
    End Sub
End Class

' ファクトリーパターンの使用例
Dim factory, animal
Set factory = New AnimalFactory
Set animal = factory.CreateAnimal("Dog")
animal.Speak()

ファクトリークラスが、オブジェクトの生成を担当し、クライアント側は動物の種類だけを指定すれば、具体的なオブジェクトの生成はファクトリに任せることができます。

ストラテジーパターン

ストラテジーパターンでは、異なるアルゴリズムをクラスとして定義し、状況に応じてそれらを動的に切り替えることが可能です。

Class Context
    Private strategy
    
    Public Sub SetStrategy(s)
        Set strategy = s
    End Sub
    
    Public Sub ExecuteStrategy()
        strategy.Algorithm
    End Sub
End Class

Class StrategyA
    Public Sub Algorithm()
        MsgBox "Strategy A"
    End Sub
End Class

Class StrategyB
    Public Sub Algorithm()
        MsgBox "Strategy B"
    End Sub
End Class

' ストラテジーパターンの使用例
Dim context, strategyA, strategyB
Set context = New Context
Set strategyA = New StrategyA
Set strategyB = New StrategyB

' Strategy A を使用
context.SetStrategy strategyA
context.ExecuteStrategy()

' Strategy B に切り替え
context.SetStrategy strategyB
context.ExecuteStrategy()

クライアントは、Contextクラスを通じて異なる戦略(アルゴリズム)を動的に変更することができます。

オブザーバーパターン

オブザーバーパターンでは、あるオブジェクトの状態が変化した際に、その変化を監視している他のオブジェクト(オブザーバー)に通知します。

このパターンは、イベント駆動型のプログラムでよく使用されます。

Class Subject
    Private observers
    
    Private Sub Class_Initialize()
        Set observers = CreateObject("Scripting.Dictionary")
    End Sub
    
    Public Sub AddObserver(o)
        observers.Add observers.Count + 1, o
    End Sub
    
    Public Sub NotifyObservers()
        Dim o
        For Each o In observers
            o.Update
        Next
    End Sub
End Class

Class Observer
    Public Sub Update()
        MsgBox "Observer Notified!"
    End Sub
End Class

' オブザーバーパターンの使用例
Dim subject, observer1, observer2
Set subject = New Subject
Set observer1 = New Observer
Set observer2 = New Observer

subject.AddObserver observer1
subject.AddObserver observer2

' 状態変更を通知
subject.NotifyObservers()

この例では、Subjectが複数のObserverを持ち、NotifyObserversメソッドを呼び出すことで、全てのオブザーバーに通知します。

デコレーターパターン

デコレーターパターンでは、オブジェクトに動的に機能を追加することができます。

基本的なクラスに対して、追加の責務を与えるために使用されます。

Class Component
    Public Sub Operation()
        MsgBox "Basic Operation"
    End Sub
End Class

Class Decorator
    Private component
    
    Public Sub SetComponent(c)
        Set component = c
    End Sub
    
    Public Sub Operation()
        component.Operation
        MsgBox "Added Operation by Decorator"
    End Sub
End Class

' デコレーターパターンの使用例
Dim component, decorator
Set component = New Component
Set decorator = New Decorator

decorator.SetComponent component
decorator.Operation()

DecoratorクラスがComponentクラスをラップし、元の機能に加えて追加の動作を実行します。


デザインパターンの適用例

これまでに紹介したパターンは、さまざまな場面で利用できます。

シングルトンパターンは設定情報の管理、ファクトリーパターンはオブジェクト生成の集中管理に役立ちます。

ストラテジーパターンは異なるアルゴリズムを容易に切り替えたい場合、オブザーバーパターンはイベント通知システムの設計に、デコレーターパターンは既存のオブジェクトに機能を追加する場合に使えます。


まとめ

この記事では、VBScriptでのデザインパターンの実装を紹介しました。

シングルトン、ファクトリー、ストラテジー、オブザーバー、デコレーターパターンといった代表的なデザインパターンを使うことで、再利用性の高い保守性のあるコードが書けるようになります。

VBScriptはオブジェクト指向プログラミングの機能が限定的ですが、デザインパターンを適用することで効率的な設計が可能です。


演習問題と解答例

この記事の内容を基にした演習問題を通じて、実際に手を動かしながら学習を進めましょう。

演習問題1: オブザーバーパターンの実装

NewsPublisherクラスを作成し、複数のSubscriberクラスがそのニュースを購読して通知を受け取る仕組みを実装してください。

ニュースが更新された際に、全ての購読者に通知が送られるようにしてください。

演習1:解答例
Class NewsPublisher
    Private subscribers
    
    Private Sub Class_Initialize()
        Set subscribers = CreateObject("Scripting.Dictionary")
    End Sub
    
    Public Sub AddSubscriber(s)
        subscribers.Add subscribers.Count + 1, s
    End Sub
    
    Public Sub NotifySubscribers(news)
        Dim s
        For Each s In subscribers
            s.Update(news)
        Next
    End Sub
End Class

Class Subscriber
    Public Sub Update(news)
        MsgBox "Received News: " & news
    End Sub
End Class

' 使用例
Dim publisher, subscriber1, subscriber2
Set publisher = New NewsPublisher
Set subscriber1 = New Subscriber
Set subscriber2 = New Subscriber

publisher.AddSubscriber subscriber1
publisher.AddSubscriber subscriber2

' ニュースを通知
publisher.NotifySubscribers "New Article Published!"

演習問題2: デコレーターパターンの実装

Carクラスに、Driveメソッドを持たせ、デコレーターでSportsCarやLuxuryCarとして追加機能(例えば、スピードの表示や快適なドライブメッセージ)を付け加える実装をしてください。

演習2:解答例
Class Car
    Public Sub Drive()
        MsgBox "Driving a car."
    End Sub
End Class

Class SportsCarDecorator
    Private car
    
    Public Sub SetCar(c)
        Set car = c
    End Sub
    
    Public Sub Drive()
        car.Drive
        MsgBox "Driving fast with a sports car!"
    End Sub
End Class

Class LuxuryCarDecorator
    Private car
    
    Public Sub SetCar(c)
        Set car = c
    End Sub
    
    Public Sub Drive()
        car.Drive
        MsgBox "Driving in luxury!"
    End Sub
End Class

' 使用例
Dim car, sportsCar, luxuryCar
Set car = New Car
Set sportsCar = New SportsCarDecorator
Set luxuryCar = New LuxuryCarDecorator

sportsCar.SetCar car
luxuryCar.SetCar car

' スポーツカーとして運転
sportsCar.Drive()

' ラグジュアリーカーとして運転
luxuryCar.Drive()