202401015エクセルVBA オブジェクト指向備忘録 デザインパターン ファクトリー
<前書き>
エクセルVBAオブジェクト指向、初心者です。
VBA自体は、以前から使用していました。
オブジェクト指向というものがあることは、知っていましたが、ネットなどを見てもよく分からず、挫折した過去あり。
<以上前書き>
(素人なので間違っているかもしれません。汗。)
ここ最近、クラス、オブジェクト指向をやってきて、思ったこととしたことの?備忘録(未確認・未確定メモ)です。
(素人なので間違っているかも。汗)
最近、VBAで、OOP(オブジェクト指向プログラミング)について、意識しながら、コードを書いているのですが、今回も自分用のメモを書きます。
今回は、「ファクトリー」です。
でも、正しい使い方かは分かりません。汗。
<前知識>
前回同様youtubeで、「独り言のプログラミング」というのを見ました。
C#に関するものですが、分かりやすい気がします。感謝。
(不都合があれば、削除いたします。)
その動画の中でファクトリーに関して、下記のような説明がありました。
(少し変えてます。)
もとに、A→B(リンゴと表示)というコードがあり、
それを利用して、→C(みかんと表示)するコードを作成する感じでした。
(ただし、後から追加設定するのではなく、設計当初から考えられるのがファクトリーだとか。)
で、自分にとって、新鮮だったのは、A’の存在です。
(同一のAからのBとCへの枝分かれではなかったです。)
動画で紹介されていたのは、C#なので、よく分かっていませんが、
クラスAがあり、
クラスA’(AEx)は、クラスAを継承。
クラスB、クラスCをインターフェース化するITectを用意。
クラスB、クラスCをインターフェース化。
クラスAでは、クラスBをインスタンス化して、リンゴを表示。
(クラスAは、ITestを作動させるため、virtualとか少し記入多い。)
クラスA’(AEx)では、クラスBをインスタンス化して、みかんを表示。
大元のコードで、下記のように、ClassAExを呼べば、みかんが表示される仕組みです。
private void button1_Click(object sender, EventArgs e){
ClassAEx obj = new ClassAEx();
obj.print();
}
図ではこんな感じ。
分かりやすい。
(余談:ただ、ファクトリーは、実際には、あまり使われないとのことでした。
上記では、Aの中でBをnewしてますが、Aの中でnewするのをやめて、Aが生成される前に、BやCを渡す方法もあるからだそうです。)
あと、何となく分かっていないのが、最後の方の説明で、
factory.getinstance(1)という感じで、引数を渡すやり方は、ファクトリーに含むか含まないか、現場によって違うような話がありました。
これは、実際には、内部で、
if(type=1)return new classB()
というようなif文を隠しているだけとのこと。
この使い方がそんなに気になるのか、自分には分かりませんでした。
<本番:VBAではどうなる?>
chatGPT4oさんに聞きました。
●最初に作成してもらったコード
プロンプトに、
factory.getinstance(1)
factory.getinstance(2)
等例示を入れました。
コードは下記です。
=============================
' ClassA.cls
Option Explicit
Public Sub ShowMessage()
MsgBox "これは ClassA のインスタンスです。"
End Sub
============================
' ClassB.cls
Option Explicit
Public Sub ShowMessage()
MsgBox "これは ClassB のインスタンスです。"
End Sub
==========================
' Factory.cls
Option Explicit
Public Function GetInstance(ByVal TypeID As Integer) As Object
Select Case TypeID
Case 1
Set GetInstance = New ClassA
Case 2
Set GetInstance = New ClassB
Case Else
MsgBox "無効なタイプIDです。"
Set GetInstance = Nothing
End Select
End Function
============================
' Module1.bas
Option Explicit
Sub TestFactoryPattern()
Dim factory As Factory
Dim obj As Object
' Factoryクラスを初期化
Set factory = New Factory
' TypeID = 1 の場合は ClassA、2 の場合は ClassB を取得
Set obj = factory.GetInstance(1) ' ClassAのインスタンス取得
If Not obj Is Nothing Then obj.ShowMessage
Set obj = factory.GetInstance(2) ' ClassBのインスタンス取得
If Not obj Is Nothing Then obj.ShowMessage
End Sub
====================================
上記でいいのかなと思ったのですが、「あれ?implements」がないなとか、
図にしたら、クラスA’(に当たるもの)がないな)とか思いました。
上記コードの図(多分)
youtubeで、「独り言のプログラミング」さんで、「Factoryではないかも・・・」というのは上記のことなのだろうか。
(・・・違う気がする。)
●次に作成してもらったコード
プロンプトは、「VBAで、デザインパターンのファクトリーの簡単なコードを書いて。」
で、できたのは下記のコードです。
==============================
' Animal.cls
Option Explicit
Public Sub Speak()
' 各サブクラスで実装するべきメソッド
MsgBox "This animal has no sound."
End Sub
=============================
' Dog.cls
Option Explicit
Implements Animal
Private Sub Animal_Speak()
MsgBox "ワンワン! (Woof Woof!)"
End Sub
=============================
' Cat.cls
Option Explicit
Implements Animal
Private Sub Animal_Speak()
MsgBox "ニャーニャー! (Meow Meow!)"
End Sub
=============================
' AnimalFactory.cls
Option Explicit
Public Function CreateAnimal(ByVal animalType As String) As Animal
Select Case animalType
Case "Dog"
Set CreateAnimal = New Dog
Case "Cat"
Set CreateAnimal = New Cat
Case Else
MsgBox "Invalid animal type."
Set CreateAnimal = Nothing
End Select
End Function
============================
' Module1
Option Explicit
Sub TestFactoryPattern()
Dim factory As New AnimalFactory
Dim animal As Animal
' 犬のインスタンスを生成
Set animal = factory.CreateAnimal("Dog")
If Not animal Is Nothing Then animal.Speak
' 猫のインスタンスを生成
Set animal = factory.CreateAnimal("Cat")
If Not animal Is Nothing Then animal.Speak
' 存在しない動物を指定
Set animal = factory.CreateAnimal("Bird")
If Not animal Is Nothing Then animal.Speak
End Sub
==========================
よくある動物のimplementsを使ったコードです。
図にすると下記の感じ。(縦にしました。)
今度のは、implementsで、DogとCatができるから、一番最初の例のクラスAとクラスA’(AEx)
と考えていいのか?
良くわかなない。
ただ、Dogクラスの下に、クラスC
Catクラスの下にクラスDを持って来て、全体をファクトリーパターンだということはできるかも。
あまりしっくりこないが、深追いはやめる。そのうち分かるかも。
202401015エクセルVBA オブジェクト指向備忘録 デザインパターン ファクトリー追記
追記 さんざん書いたけど、上記コードはyoutube「独り言のプログラミング」様のC#のコードの再現ではなく、そもそも違っているようです。
間違いや変な引用の仕方で申し訳ない。自分用のメモということで許して下さい。
下記のコードが書き替えに近いか。
====================
'標準module
Sub Button1_Click()
Dim obj As ClassAEx
Set obj = New ClassAEx
' Dim obj As ClassA
' Set obj = New ClassA
obj.TPrint
End Sub
' クラスモジュール名: ClassA
Option Explicit
Public Sub TPrint()
Dim obj As ITest
Set obj = Me.Create()
MsgBox obj.GetMsg()
End Sub
Public Function Create() As ITest
' デフォルトでClassBのインスタンスを返す
Set Create = New ClassB
End Function
' クラスモジュール名: ClassAEx
Option Explicit
' ClassAを拡張したクラス
Public Sub TPrint() '追加
Dim obj As ITest
Set obj = Me.Create 'Meを修正
MsgBox obj.GetMsg()
End Sub
Function Create() As ITest 'private修正
' ClassCのインスタンスを返す
Set Create = New ClassC
End Function
' クラスモジュール名: ClassB
Option Explicit
Implements ITest
Private Function ITest_GetMsg() As String
ITest_GetMsg = "りんご"
End Function
' クラスモジュール名: ClassC
Option Explicit
Implements ITest
Private Function ITest_GetMsg() As String
ITest_GetMsg = "みかん"
End Function
' クラスモジュール名: ITest
Option Explicit
Public Function GetMsg() As String
' 継承先で実装する
End Function
==================
これだと、この図の仕組み通りです。(継承はできていないけど。)
(ラップしていないといえばいいのかな。)