Class Factories - Parameterized Object Initialisation (2 Viewers)

dalski

Member
Local time
Today, 00:30
Joined
Jan 5, 2025
Messages
195
Trying to learn Implementation Classes & Class Factories - Parameterized Object Initialisation from this great tutorial,but I get the pic'd error & I can't see where I'm going wrong? I've Predeclared the classes as per tutorial. I'm just before he turns it into an Abstract Factory. I also tried it before creating the cISomethingFactory & got the same error, but in my mind that should have worked.

I'm unsure what the benefit of using a Type for the Properties of the Implementation Class & why he's not using typical module level variables but that's besides the point atm & I can experiment once I get it working.

1759858670119.png


cSomething
Code:
Private Type TSomething
  Bar As Long
  Ducky As String
End Type

Private this As TSomething
Implements cISomething
Implements cISomethingFactory

Public Function Create(ByVal initialBar As Long, ByVal initialDucky As String) As cISomething
  With New cSomething
    .Bar = initialBar
    .Ducky = initialDucky
    Set Create = .Self
  End With
End Function

Public Property Get Self() As cISomething
  Set Self = Me
End Property

Public Property Get Bar() As Long
  Bar = this.Bar
End Property
Friend Property Let Bar(ByVal NewValue As Long)
  this.Bar = NewValue
End Property
Public Property Get Ducky() As String
  Ducky = this.Ducky
End Property
Friend Property Let Ducky(ByVal NewValue As String)
  this.Ducky = NewValue
End Property


Private Property Get ISomething_Bar() As Long
  ISomething_Bar = Bar
End Property
Private Property Get ISomething_Ducky() As Long
  ISomething_Ducky = Ducky
End Property


Private Function cISomethingFactory_Create(ByVal initialBar As Long, ByVal initialDuck As String) As cISomething
  Set cISomethingFactory_Create = Create(initialBar, initialDuck)
End Function

cISomething
Code:
Public Property Get Bar() As Long
End Property

Public Property Get Ducky() As String
End Property

cISomethingFactory
Code:
Public Property Get Bar() As Long
End Property

Public Property Get Ducky() As String
End Property

Public Function Create(ByVal initialBar As Long, ByVal initialDuck As String) As cISomething
End Function

ModTest
Code:
Sub testImplementClass()
  Dim obj As cSomething
  With obj.Create(5, "Quack")
    Debug.Print .Bar
  End With
End Sub
 

Attachments

Private Property Get ISomething_Bar() As Long
ISomething_Bar = Bar
End Property
Private Property Get ISomething_Ducky() As Long
ISomething_Ducky = Ducky
End Property


cISomething
Code:
Public Property Get Bar() As Long
End Property

Public Property Get Ducky() As String
End Property

Since you defined the interface class "cISomething", shouldn't the implementation functions have that name.

Code:
Private Property Get cISomething_Bar() As Long
  ISomething_Bar = Bar
End Property

Private Property Get cISomething_Ducky() As Long
  ISomething_Ducky = Ducky
End Property

IMO
The type for member variables makes it much easer to reference with each variable using one known instance variable "This".
 
Thanks Ron & for explaining the benefit of the Type in the tutorial.

Oh I see (thank you); I missed the 'c' in ISomething_Bar in cSomething should be cISomething_Bar & ditto for Ducky. Regardless after fixing that the compiler is still throwing the same error "Object Module needs to implement 'Bar' for interface cIsomethingFactory", which I do not understand why that's happening but in much feedback in the tutorial no-one else has any problems with it.
 
Oh I see (thank you); I missed the 'c' in ISomething_Bar in cSomething should be cISomething_Bar & ditto for Ducky. Regardless after fixing that the compiler is still throwing the same error "Object Module needs to implement 'Bar' for interface cIsomethingFactory", which I do not understand why that's happening but in much feedback in the tutorial no-one else has any problems with it.

In cISomethingFactory you define get properties for Bar and Ducky which are not needed, you can comment them out.

in cSomething you are retuning the wrong type.
Code:
'Private Property Get cISomething_Ducky() As Long
Private Property Get cISomething_Ducky() As String
  cISomething_Ducky = Ducky
End Property

in testImplementClass you need to define obj with new.

Code:
Sub testImplementClass()
'  Dim obj As cSomething
  Dim obj As New cSomething
  With obj.Create(5, "Quack")
    Debug.Print .Bar
  End With
End Sub
 
cSomething was missing the below; as the Implementation Class' blueprint (members of the Implementation Class) must be followed wherever it is implemented. The compiler needs to see code-stubs for them members.

Code:
Private Property Get cISomethingFactory_Bar() As Long
  cISomethingFactory_Bar = Bar
End Property
Private Property Get cISomethingFactory_Ducky() As String
  cISomethingFactory_Ducky = Ducky
End Property

I also stupidly had a Ducky property as the wrong data-type (apologies). So now she compiles. But when testing in the Testing module I get 'Object Variable or With block variable not set'; the entire purpose of the exercise :ROFLMAO:.

Code:
Sub testImplementClass()
  Dim obj As cSomething
  With obj.Create(5, "Quack")
    Debug.Print .Bar
  End With
End Sub

The testing module should be able to access the public function Create in the cSomething. Then implement cISomething to get the properties Bar & Ducky. Then create an instance with the Property Self.

Seems superfluous why duplicate properties are in the cSomething; Bar & Ducky. One would think these would be used through the Implementation class.:eek:
 
cSomething was missing the below; as the Implementation Class' blueprint (members of the Implementation Class) must be followed wherever it is implemented. The compiler needs to see code-stubs for them members.

Code:
Private Property Get cISomethingFactory_Bar() As Long
  cISomethingFactory_Bar = Bar
End Property
Private Property Get cISomethingFactory_Ducky() As String
  cISomethingFactory_Ducky = Ducky
End Property

I also stupidly had a Ducky property as the wrong data-type (apologies). So now she compiles. But when testing in the Testing module I get 'Object Variable or With block variable not set'; the entire purpose of the exercise :ROFLMAO:.

Code:
Sub testImplementClass()
  Dim obj As cSomething
  With obj.Create(5, "Quack")
    Debug.Print .Bar
  End With
End Sub

The testing module should be able to access the public function Create in the cSomething. Then implement cISomething to get the properties Bar & Ducky. Then create an instance with the Property Self.

Seems superfluous why duplicate properties are in the cSomething; Bar & Ducky. One would think these would be used through the Implementation class.:eek:
I think you missed a step in the tutorial. To add the attribute, you must export the class module to a text file, then open it in a text editor like Notepad, add the attribute text. then import the text file back into your database. The attribute creates an instance of the class when you FE runs that you can access using the class name. Now you will not need NEW to use create.

itself, and there’s a VB_Attribute in the class header that you need to tweak to activate it:

VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "Something" '#FunFact controlled by the "Name" property of the class module
Attribute VB_GlobalNameSpace = False '#FunFact VBA ignores this attribute
Attribute VB_Creatable = False '#FunFact VBA ignores this attribute
[SIZE=7]Attribute VB_PredeclaredId = [/SIZE]True [SIZE=7]'<~ HERE![/SIZE]
Attribute VB_Exposed = False '#FunFact controlled by th
[td width="auto"]
1
2
3
4
5
6
7
8
9​
[/td]
 
I missed the 'c' in ISomething_Bar in cSomething should be cISomething_Bar
I'd rather suggest you do not rename the interface with your c prefix.
It is not a class but an interface. These are technically the same in VBA but their purpose is different.
It is a common convention to name interfaces with a capital I at the beginning.
 
Thanks Ron, sorry I posted at just after your helpful post. Yes that works, thank you. I had predeclared the classes. As you kindly pointed out missed the below in the external sub as I was confused with what was going on:

Code:
Set obj = cSomething

I started to understand what was going on before I attempted the last stage (CreateFromFactory). We were actually using the properties in the cISomething ISomething (thanks Sonic8) (Implementation Class) as values for the Self function in cSomething. Which are convulated populated by the cSomething properties sharing the same name. I don't know if this is the best e.g. that could have been given to illustrates this. It must be awkward to explain it but this seemed to really obfuscate what was going on for me.
The properties in cISomething ISomething are still needed though I think, because when we fetch the values externally in the testImplementClass sub; the values returned are actually returned from ISomething_Ducky/ ISomething_Bar. Which is obfuscated by the Get properties in cSomething which strangely act like a Let; assigning the value from the types in cSomething to the ISomething interface. Or at least did up till the final stage below:


Final Stage
Moving onto the 'Abstract Factory' where a macro from god knows where appears with no explanation whatsoever in the tutorial (which I've omitted in my main module code I'm not firing correctly. He has the tutorial as

Code:
Public Sub Main()
    Dim factory As ISomethingFactory
    Set factory = Something.Self
    With MyMacro.Create(factory)
        .Run
    End With
End Sub

Seems strange just to reference the cSomething.Self as no arguments have been provided to initialise the object. So I put

Code:
Sub TestAbstractFactory()
  Dim factory As ISomethingFactory
  Set factory = cSomething.CreateFromFactory(8, "hat")
  Debug.Print cSomething.Bar
End Sub

But I loose the values when it debugs. :eek: Unlike before where the values remained intact. Sorry not doing well here; been a 15 hour day. Calling it a day now.

1759875852209.png
 

Attachments

Thanks Ron, sorry I posted at just after your helpful post. Yes that works, thank you. I had predeclared the classes. As you kindly pointed out missed the below in the external sub as I was confused with what was going on:

Code:
Set obj = cSomething

I started to understand what was going on before I attempted the last stage (CreateFromFactory). We were actually using the properties in the cISomething ISomething (thanks Sonic8) (Implementation Class) as values for the Self function in cSomething. Which are convulated populated by the cSomething properties sharing the same name. I don't know if this is the best e.g. that could have been given to illustrates this. It must be awkward to explain it but this seemed to really obfuscate what was going on for me.
The properties in cISomething ISomething are still needed though I think, because when we fetch the values externally in the testImplementClass sub; the values returned are actually returned from ISomething_Ducky/ ISomething_Bar. Which is obfuscated by the Get properties in cSomething which strangely act like a Let; assigning the value from the types in cSomething to the ISomething interface. Or at least did up till the final stage below:


Final Stage
Moving onto the 'Abstract Factory' where a macro from god knows where appears with no explanation whatsoever in the tutorial (which I've omitted in my main module code I'm not firing correctly. He has the tutorial as

Code:
Public Sub Main()
    Dim factory As ISomethingFactory
    Set factory = Something.Self
    With MyMacro.Create(factory)
        .Run
    End With
End Sub

Seems strange just to reference the cSomething.Self as no arguments have been provided to initialise the object. So I put

Code:
Sub TestAbstractFactory()
  Dim factory As ISomethingFactory
  Set factory = cSomething.CreateFromFactory(8, "hat")
  Debug.Print cSomething.Bar
End Sub

But I loose the values when it debugs. :eek: Unlike before where the values remained intact. Sorry not doing well here; been a 15 hour day. Calling it a day now.

View attachment 121768

With pre-declare true you test code needs no define.

Code:
Sub testImplementClass()
  With cSomething.Create(5, "Quack")
    Debug.Print .Bar
  End With
End Sub

With a single class, interface makes little sense but multiple classes implementing the same interface allow you to some interesting things. The biggest issue I have with factory in VBA is requiring the pre-declare attribute; all classes with a factory will have an instance from start of the application to the end.
 

Users who are viewing this thread

Back
Top Bottom