Design Question for Factory Pattern and Casting Types

G

Guest

Accidently posted this to the wrong group so I am reposting.
This is probably a newbie question but I am a little confused about how to go
next with my code. I think I want to use a factory pattern in this situation
but I am having trouble getting access to properties at the presentation
level. So my situation is I have a Vehicle base class.

Public Class Vehicle
Property BodyType as String
End Class

Then I have multiple inherited Classes
Public Class Truck inherits Vehicle
Property Weight as String
End Class

Public Class Forklift inherits Vehicle
Property EngineType as String
End Class

My factory uses a select statement on the Body Type to decide which class to
instantiate.
Public Class VehicleFactory
Public Shared Function CreateVehicleInstance(bodyType as String) as Vehicle
Select Case bodyType
Case "Truck"
return v as New Truck
Case "Forklift"
return v as New Forklift
End Select
return v
End Function
End Class

My problems comes when I try return my class from the factory and access
properties of the inherited class. The compiler won't let me compile it and I
am not sure where to go. So for exampl

Dim v as Vehicle = VehicleFactory.CreateVehicleInstance("Truck")

v.Weight = 6 'this give me a compile error that Weight is not a member of
the base class

I am trying to use this on the form and once the object is created then I
need it accesible to the form to track whether it needs to be saved back to
the database or not. Am I going about this all wrong?
 
J

jayeldee

You probably want to change..
Dim v as Vehicle = VehicleFactory.CreateVehicleInstance("Truck")
to
Dim t as Truck = VehicleFactory.CreateVehicleInstance("Truck")
so you can access the Truck variables.
 
G

Guest

Right I understand that I would rather cast to the Truck, but the problem is
that the type of object is specified at runtime. I want to create an object
on my main form that all my child forms have access to. But I don't know
which sub class of my family of vehicles the user will choose at runtime.
That's why I thought about using the Ctype function, but then I don't have
access to properties in the subclass and I get a compile error.
 
G

Guest

Can't you try something like:

If TypeOf (v) Is Truck Then
CType(v, Truck).Weight = "6"
End If
 
G

Guest

I was hoping that someone might know how to to cast the type so I would have
to do a switch statement everytime I had to deal with this object. I want to
have a variable that is part of my form, that way once it is instantiated
then I don't have to worry about the types. This is a big problem because the
Truck is not the only vehicle that I will be dealing with. I think I am going
about this wrong, but I can't figure out the right way to do it.

I have a main form that they will enter the the vehicle information and then
there will be other forms that build off the main one. I guess maybe how
could I create an object when the user clicks the "Save" button and not let
it get out of scope while the form is open. The only way I know to do this is
to create a Private variable, but you have to give it a type and then I can
instantiate it, but when the form loads I don't know the type. I guess I need
to re-think this.
 
G

Guest

You can try something like this. You can create a series of interfaces and
abstract classes for your vehicles. You can also then create an "instance"
class that will hold your current instance of any vehicle created from the
factory. From there, you can pass it around to anyform you wish, and not
have to worry about the type it is.

The Below code is not throughly tested and is propably not the most ideal
design, but it does get the point across and can perhaps serve as a starting
point for you. Modify it as you see fit:

Public Interface IVehicle

ReadOnly Property BodyType() As String

End Interface

Public Interface ITruck

Property Weight() As String

End Interface

Public Interface IForklift

Property EngineType() As String

End Interface

Public MustInherit Class Vehicle
Implements IVehicle

Protected bodyT As String

Public Sub New()

End Sub

Public Sub New(ByVal bdyTp As String)
Me.bodyT = bdyTp
End Sub

Public ReadOnly Property BodyType() As String Implements IVehicle.BodyType
Get
Return Me.bodyT
End Get
End Property

End Class

Public Class Truck
Inherits Vehicle
Implements ITruck

Private wt As String


Public Sub New(ByVal bdyTp As String)
Me.bodyT = bdyTp
End Sub

Public Property Weight() As String Implements ITruck.Weight
Get
Return Me.wt
End Get
Set(ByVal Value As String)
'Validate that Value is a valid weight, if it is assign it
Me.wt = Value
End Set
End Property

End Class

Public Class Forklift
Inherits Vehicle
Implements IForklift

Private engineT As String

Public Sub New(ByVal bdyTp As String)
Me.bodyT = bdyTp
End Sub

Public Property EngineType() As String Implements IForklift.EngineType
Get
Return Me.engineT
End Get
Set(ByVal Value As String)
'Validate that Value is a valid EngineType
Me.engineT = Value
End Set
End Property

End Class

Public Class VehicleFactory

Public Shared Function CreateVehicle(ByVal bdyTyp As String) As Vehicle

Dim asm As [Assembly]
Dim asmTypes() As Type

'Create an instance of the executing assembly
asm = [Assembly].GetExecutingAssembly()

'Get a list of types from the current executing assembly
asmTypes = asm.GetTypes()

Dim typeNamespace As String
Dim typeToLookFor As String

For Each currentType As Type In asmTypes

'Derive the namespace of the current type of the list
typeNamespace = currentType.Namespace

'Derive the fully qualified name of the type we are looking for
typeToLookFor = typeNamespace & "." & bdyTyp

'If the current type matches the type we are looking for, return
an instance of it.
'The comparison is case sensitive
If String.Compare(typeToLookFor, currentType.FullName, False) =
0 Then
'Create the parameters for the constructor
Dim args() As Object = {bdyTyp}
Return Activator.CreateInstance(currentType, args)
End If

Next

'If we get this far, the type we were looking was not found in the
assembly
Throw New Exception("The type " & bdyTyp & " was not found in the
assembly.")

End Function

End Class

Public Class VehicleInstance
Implements IVehicle, ITruck, IForklift

Private m_currentVehicle As Vehicle

Public Sub New(ByVal bdyT As String)

Me.m_currentVehicle = VehicleFactory.CreateVehicle(bdyT)

End Sub

Public Property EngineType() As String Implements IForklift.EngineType
Get
If TypeOf (Me.m_currentVehicle) Is Forklift Then
Return CType(Me.m_currentVehicle, Forklift).EngineType
Else
'Either return Nothing, Empty String, Or Throw Exception
End If
End Get
Set(ByVal Value As String)

If TypeOf (Me.m_currentVehicle) Is Forklift Then
CType(Me.m_currentVehicle, Forklift).EngineType = Value
Else
'Throw exception or something else
End If

End Set
End Property

Public Property Weight() As String Implements ITruck.Weight
Get
If TypeOf (Me.m_currentVehicle) Is Truck Then
Return CType(Me.m_currentVehicle, Truck).Weight
Else
'Either return Nothing, Empty String, Or Throw Exception
End If
End Get
Set(ByVal Value As String)
If TypeOf (Me.m_currentVehicle) Is Truck Then
CType(Me.m_currentVehicle, Truck).Weight = Value
Else
'Throw exception or something else
End If
End Set
End Property

Public ReadOnly Property BodyType() As String Implements IVehicle.BodyType
Get
Return Me.m_currentVehicle.BodyType
End Get
End Property
End Class

Sub Main()

Dim v As New VehicleInstance("Truck")

v.Weight = 6

End Sub
 
G

Guest

That looks pretty cool. I will try this thanks.

rmacias said:
You can try something like this. You can create a series of interfaces and
abstract classes for your vehicles. You can also then create an "instance"
class that will hold your current instance of any vehicle created from the
factory. From there, you can pass it around to anyform you wish, and not
have to worry about the type it is.

The Below code is not throughly tested and is propably not the most ideal
design, but it does get the point across and can perhaps serve as a starting
point for you. Modify it as you see fit:

Public Interface IVehicle

ReadOnly Property BodyType() As String

End Interface

Public Interface ITruck

Property Weight() As String

End Interface

Public Interface IForklift

Property EngineType() As String

End Interface

Public MustInherit Class Vehicle
Implements IVehicle

Protected bodyT As String

Public Sub New()

End Sub

Public Sub New(ByVal bdyTp As String)
Me.bodyT = bdyTp
End Sub

Public ReadOnly Property BodyType() As String Implements IVehicle.BodyType
Get
Return Me.bodyT
End Get
End Property

End Class

Public Class Truck
Inherits Vehicle
Implements ITruck

Private wt As String


Public Sub New(ByVal bdyTp As String)
Me.bodyT = bdyTp
End Sub

Public Property Weight() As String Implements ITruck.Weight
Get
Return Me.wt
End Get
Set(ByVal Value As String)
'Validate that Value is a valid weight, if it is assign it
Me.wt = Value
End Set
End Property

End Class

Public Class Forklift
Inherits Vehicle
Implements IForklift

Private engineT As String

Public Sub New(ByVal bdyTp As String)
Me.bodyT = bdyTp
End Sub

Public Property EngineType() As String Implements IForklift.EngineType
Get
Return Me.engineT
End Get
Set(ByVal Value As String)
'Validate that Value is a valid EngineType
Me.engineT = Value
End Set
End Property

End Class

Public Class VehicleFactory

Public Shared Function CreateVehicle(ByVal bdyTyp As String) As Vehicle

Dim asm As [Assembly]
Dim asmTypes() As Type

'Create an instance of the executing assembly
asm = [Assembly].GetExecutingAssembly()

'Get a list of types from the current executing assembly
asmTypes = asm.GetTypes()

Dim typeNamespace As String
Dim typeToLookFor As String

For Each currentType As Type In asmTypes

'Derive the namespace of the current type of the list
typeNamespace = currentType.Namespace

'Derive the fully qualified name of the type we are looking for
typeToLookFor = typeNamespace & "." & bdyTyp

'If the current type matches the type we are looking for, return
an instance of it.
'The comparison is case sensitive
If String.Compare(typeToLookFor, currentType.FullName, False) =
0 Then
'Create the parameters for the constructor
Dim args() As Object = {bdyTyp}
Return Activator.CreateInstance(currentType, args)
End If

Next

'If we get this far, the type we were looking was not found in the
assembly
Throw New Exception("The type " & bdyTyp & " was not found in the
assembly.")

End Function

End Class

Public Class VehicleInstance
Implements IVehicle, ITruck, IForklift

Private m_currentVehicle As Vehicle

Public Sub New(ByVal bdyT As String)

Me.m_currentVehicle = VehicleFactory.CreateVehicle(bdyT)

End Sub

Public Property EngineType() As String Implements IForklift.EngineType
Get
If TypeOf (Me.m_currentVehicle) Is Forklift Then
Return CType(Me.m_currentVehicle, Forklift).EngineType
Else
'Either return Nothing, Empty String, Or Throw Exception
End If
End Get
Set(ByVal Value As String)

If TypeOf (Me.m_currentVehicle) Is Forklift Then
CType(Me.m_currentVehicle, Forklift).EngineType = Value
Else
'Throw exception or something else
End If

End Set
End Property

Public Property Weight() As String Implements ITruck.Weight
Get
If TypeOf (Me.m_currentVehicle) Is Truck Then
Return CType(Me.m_currentVehicle, Truck).Weight
Else
'Either return Nothing, Empty String, Or Throw Exception
End If
End Get
Set(ByVal Value As String)
If TypeOf (Me.m_currentVehicle) Is Truck Then
CType(Me.m_currentVehicle, Truck).Weight = Value
Else
'Throw exception or something else
End If
End Set
End Property

Public ReadOnly Property BodyType() As String Implements IVehicle.BodyType
Get
Return Me.m_currentVehicle.BodyType
End Get
End Property
End Class

Sub Main()

Dim v As New VehicleInstance("Truck")

v.Weight = 6

End Sub

GarrettD78 said:
I was hoping that someone might know how to to cast the type so I would have
to do a switch statement everytime I had to deal with this object. I want to
have a variable that is part of my form, that way once it is instantiated
then I don't have to worry about the types. This is a big problem because the
Truck is not the only vehicle that I will be dealing with. I think I am going
about this wrong, but I can't figure out the right way to do it.

I have a main form that they will enter the the vehicle information and then
there will be other forms that build off the main one. I guess maybe how
could I create an object when the user clicks the "Save" button and not let
it get out of scope while the form is open. The only way I know to do this is
to create a Private variable, but you have to give it a type and then I can
instantiate it, but when the form loads I don't know the type. I guess I need
to re-think this.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top