Damian
Damian

Reputation: 5174

Creating Class properties with sub levels

I've been reading this topic on how to use class modules.

My goal is to improve my code performance and readability so I think I'm in the right path.

But I have some questions about the limitations.

In my head i want to do this:

enter image description here

Is it possible to achieve such a structure?

The topic I've read has very few examples and this is not handled. I'm assuming this would be possible with collections of collections, but I not sure how to look for this.

My data comes from 2 tables, one has all the items but the department and the other one has the ID's alongisde the departments. Both tables have the dates of the current month as headers and their Schedule/Department depending on the table.

I'd know how to achieve this for one day, but not for a whole month.

This is how I wrote the basics for my class:

Option Explicit
Private DirNeg As String
Private Agrup As String
Private DNI As String
Private Centro As String
Private Servicio As String
Private Nombre As String
Property Get Business() As String
    Business = DirNeg
End Property
Property Let Business(ByVal sBusiness As String)
    DirNeg = sBusiness
End Property
Property Get Group() As String
    Group = Agrup
End Property
Property Let Group(ByVal sGroup As String)
    Agrup = sGroup
End Property
Property Get ID() As String
    ID = DNI
End Property
Property Let ID(ByVal sID As String)
    DNI = sID
End Property
Property Get Location() As String
    Location = Centro
End Property
Property Let Location(ByVal sLocation As String)
    Centro = sLocation
End Property
Property Get Service() As String
    Service = Servicio
End Property
Property Let Service(ByVal sService As String)
    Servicio = sService
End Property
Property Get Name() As String
    Name = Nombre
End Property
Property Let Name(ByVal sName As String)
    Nombre = sName
End Property

On the other hand, is it correct to fill the whole class on the Class_Initializeevent? My data will always be the same so I don't need to loop in a normal module to fill the class, it could be done everytime the class is created.

EDIT/UPDATE:

This is how my data looks like:

Schedules alongside Agent's info

enter image description here

Departments alongside Agent's ID

enter image description here

clAgent Class Module:

Option Explicit
Private DirNeg As String
Private Agrup As String
Private DNI As String
Private Centro As String
Private Servicio As String
Private Nombre As String
Private Fechas As Object
Property Get Business() As String
    Business = DirNeg
End Property
Property Let Business(ByVal sBusiness As String)
    DirNeg = sBusiness
End Property
Property Get Group() As String
    Group = Agrup
End Property
Property Let Group(ByVal sGroup As String)
    Agrup = sGroup
End Property
Property Get ID() As String
    ID = DNI
End Property
Property Let ID(ByVal sID As String)
    DNI = sID
End Property
Property Get Location() As String
    Location = Centro
End Property
Property Let Location(ByVal sLocation As String)
    Centro = sLocation
End Property
Property Get Service() As String
    Service = Servicio
End Property
Property Let Service(ByVal sService As String)
    Servicio = sService
End Property
Property Get Name() As String
    Name = Nombre
End Property
Property Let Name(ByVal sName As String)
    Nombre = sName
End Property
Property Get clFechas(ByVal StringKey As String) As clFechas
    With Fechas
        If Not .Exists(StringKey) Then
            Dim objFechas As New clFechas
            .Add StringKey, objFechas
        End If
    End With

End Property
Private Sub Class_Initialize()

    Set Fechas = CreateObject("Scripting.Dictionary")

End Sub

clFechas Class Module:

Option Explicit
Private Modos As Object
Private Horarios As Object
'Aqiço creamos la propiedad Modo para la clase Fecha
Public Property Get Modo(ByVal StringKey As String) As String
    Modo = Modos(StringKey)
End Property
Public Property Let Modo(ByVal StringKey As String, ByVal StringValue As String)
    Modos(StringKey) = StringValue
End Property
Public Property Get Keys() As Variant
    Keys = Modos.Keys
End Property
'Aquí creamos la propiedad Horario para la clase Fecha
Public Property Get Horario(ByVal StringKey As String) As String
    Modo = Horarios(StringKey)
End Property
Public Property Let Horario(ByVal StringKey As String, ByVal StringValue As String)
    Horarios(StringKey) = StringValue
End Property
Public Property Get Keys() As Variant
    Keys = Horarios.Keys
End Property
'Iniciamos la clase
Private Sub Class_Initialize()
    Set Modos = CreateObject("Scripting.Dictionary")
    Set Horarios = CreateObject("Scripting.Dictionary")
End Sub
Private Sub Class_Terminate()
    Set Modos = Nothing
    Set Horarios = Nothing
End Sub

Upvotes: 2

Views: 242

Answers (1)

Kostas K.
Kostas K.

Reputation: 8518

You don’t seem to have any issues with regular properties so let’s focus on the complex ones; Schedule and Department. Both are the same, so same rules apply to both.

The property is basically list, the date is the index and the item is an object. I personally prefer to work with dictionaries as I can look if a key exist etc.

So, your Agent class could look something like this:


Option Explicit
Private m_schedules As Object

Public Property Get Schedule(ByVal Key As Date) As Schedules
    With m_schedules
        If Not .Exists(Key) Then .Add Key, New Schedules
    End With
    Set Schedule = m_schedules(Key)
End Property

'For testing purposes - can be ommited.
Public Property Get Keys() As Variant
    Keys = m_schedules.Keys
End Property

'For testing purposes - can be ommited.
Public Property Get Count() As Long
    Count = m_schedules.Count
End Property

Private Sub Class_Initialize()
    Set m_schedules = CreateObject("Scripting.Dictionary")
End Sub

Private Sub Class_Terminate()
    Set m_schedules = Nothing
End Sub

The Schedules class:


Option Explicit
Private m_schedule As String

Public Property Get Schedule() As String
    Schedule = m_schedule
End Property
Public Property Let Schedule(ByVal param As String)
    m_schedule = param
End Property

Now, let's test it:


Sub Test()

    Dim obj As Agent
    Set obj = New Agent

    obj.Schedule(#1/9/2019#).Schedule = "Schedule 1"
    obj.Schedule(#2/9/2019#).Schedule = "Schedule 2"
    obj.Schedule(#3/9/2019#).Schedule = "Schedule 3"

    PrintToDebug obj

    'Lets make a change
    obj.Schedule(#2/9/2019#).Schedule = "Schedule 2222"

    PrintToDebug obj

End Sub


Private Sub PrintToDebug(ByVal obj As Agent)

    Debug.Print ""

    Dim m As Variant
    With obj
        For Each m In .Keys
            Debug.Print "Key: " & m & String(3, " ") & "Value: " & .Schedule(m).Schedule
        Next m
    End With

    Debug.Print "Total Items: " & obj.Count
End Sub

Output:

'Key: 09/01/2019   Value: Schedule 1
'Key: 09/02/2019   Value: Schedule 2
'Key: 09/03/2019   Value: Schedule 3
'Total Items: 3

'Key: 09/01/2019   Value: Schedule 1
'Key: 09/02/2019   Value: Schedule 2222
'Key: 09/03/2019   Value: Schedule 3
'Total Items: 3

Additional information regarding the Dictionary object can be found here: Dictionary object

Also keep this in mind. It's quite important:

If key is not found when changing an item, a new key is created with the specified newitem. If key is not found when attempting to return an existing item, a new key is created and its corresponding item is left empty.

If the dictionary item is not a simple string, let me know to update the answer. Sorry, I couldnt read the data in the screenshots. :)

Upvotes: 2

Related Questions