Context
Usually, when I have to deal with a collection of items (especially objects) I tent to create a container class for that collection (wrapper?). What I mean by that is: when I have to handle multiple clsCar
s objects I collect them inside clsCars
class.
Building blocks
clsCar
Private pModel as String
Private pManufacturer as String
Public Property Get Model() as String
Model = pModel
End Property
Public Property Let Model(ByVal Value as String)
If Value = vbNullString Then
Error.ArgumentException vbNullString, vbNullString
End if
pModel = Value
End Property
Public Property Get Manufacturer() as String
Manufacturer = pManufacturer
End Property
To enforce a collection-like functionality would I implement a custom made ICollection
interface in each container class.
ICollection
Public Sub Add(Byref Item as Object)
End Sub
Public Sub Remove(ByVal Index as Long)
End Sub
Public Function Count() as Long
End Function
Public Function Item(ByVal Index as Long) as Object
End Function
The way I would implement this interface is as following:
clsCars
Public Sub Add(Byref Item as clsCar)
ICollection_Add Item
End Sub
Public Sub Remove(ByVal Index as Long)
ICollection_Remove Index
End Sub
Public Function Count() as Long
Count = ICollection_Count()
End Function
Public Function Item(ByVal Index as Long) as clsCar
Set Item = ICollection_Item(Index)
End Function
Private Sub ICollection_Add(Byref Item as Object)
pContent.Add Item
End Sub
Private Sub ICollection_Remove(ByVal Index as Long)
pContent.Remove Index
End Sub
Private Function ICollection_Count() as Long
ICollection_Count = pContent.Count
End Function
Private Function ICollection_Item(ByVal Index as Long) as Object
Set ICollection_Item = pContent(Index)
End Function
Sometimes, if there is a need to add a many clsCar
objects, I would create an extra AddRange
method.
clsCars
Public Sub AddRange(ByRef Items as clsCars)
If Items is Nothing Then
Error.ArgumentNullException vbNullString, vbNullString
End if
Dim Item as clsCar
For each Item in Items.Content
Me.Add Item
Next Item
Set Item = Nothing
End Sub
Finally, to iterate over items is use this dirty method. pContent
is read-only filed.
clsCars
Private pContent as New Collection
Public Property Get Content() as Collection
Set Content = pContent
End Property
But the clsCars
class is not only responsible for storing clsCar
objects, clsCars
class can also perform simple filtering using properties of clsCar
class and items inside the container. Consider:
clsCars
Public Function FilterByModel(ByVal Model as String) as clsCars
If Model = vbNullString Then
Error.ArgumentException vbNullString, vbNullString
End if
Dim Item as clsCar
Dim Output as New clsCars
For Each Item in pContent
If Item.Model = Model Then
Output.Add Item
End if
Next Item
Set FilterByModel = Output
Set Output = Nothing
Set Item = Nothing
End Function
Public Function FilterByManufacturer(ByVal Manufacturer as String) as clsCars
If Manufacturer = vbNullString Then
Error.ArgumentException vbNullString, vbNullString
End if
Dim Item as clsCar
Dim Output as New clsCars
For Each Item in pContent
If Item.Manufacturer = Manufacturer Then
Output.Add Item
End if
Next Item
Set FilterByManufacturer = Output
Set Output = Nothing
Set Item = Nothing
End Function
Implementing FilterByModel
this way would allow me to do chain-filtering if necessary.
Cars.FilterByManufacturer("Ford").FilterByModel("Focus")
Error
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "Error"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit
Public Sub ArgumentNullException(ByVal ParamName As String, ByVal Message As String)
Err.Raise 513, , "Value cannot be null." & vbNewLine & vbNewLine & _
"Additional information: " & Message & vbNewLine & vbNewLine & _
"Parameter: " & ParamName
End Sub
Public Sub ArgumentException(ByVal ParamName As String, ByVal Message As String)
Err.Raise 518, , "An exception of type ArgumentException was thrown." & vbNewLine & vbNewLine & _
"Additional information: " & Message & vbNewLine & vbNewLine & _
"Parameter: " & ParamName
End Sub
My thoughts while I was working on this:
- Each FilterBy[PropertyName] function will be very similar. I could look into this and try to find some common ground/function.
- Container class (in this case
clsCars
) will accept only specific type as an item (clsCars
will not accept, as an item, for example aclsBook
object) - I might end up with a lot of the same code which just does the same thing as
VBA.Collection
. SeeAdd(), Remove(), Count(), Item()
- It would be nice to have function which would select all
clsCar
s ifManufacturer
orModel
matches with the input. Example:MatchOr("Manufacturer = Ford Or Model = Polo")
.
Conclusion
Should I continue doing things this way? Do you see any advantages/disadvantages following this sudo-practice? I hope my lack of proper English does not hurt your eyes too much!
cls
-prefix in the name of any class module hurts my eyes much harder than any English mistakes (is that "sudo" meant to be "pseudo"?) ;-) \$\endgroup\$...actual implementation...
into the post; it's hard to review a custom collection class when all that's there is a wireframe view of it. Same for...stuff...
\$\endgroup\$