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
clsCars objects I collect them inside
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.
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:
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
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.
Private pContent as New Collection Public Property Get Content() as Collection Set Content = pContent End Property
clsCars class is not only responsible for storing
clsCars class can also perform simple filtering using properties of
clsCar class and items inside the container. Consider:
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
FilterByModel this way would allow me to do chain-filtering if necessary.
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 (
clsCarswill not accept, as an item, for example a
- I might end up with a lot of the same code which just does the same thing as
Add(), Remove(), Count(), Item()
- It would be nice to have function which would select all
Modelmatches with the input. Example:
MatchOr("Manufacturer = Ford Or Model = Polo").
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!