There are a couple of very good ansewers on the mechanics of using smple classes in VBA: When to use a Class in VBA? and What are the benefits of using Classes in VBA?
As someone relativley new to OOP and classes, it's hard to know how to implement them, or what is even really possible.
For example, I have to deal with large ranges in multiple sheets and I need to get at many different subsets of the data. "agents who does x" and "clients who have y"...etc. Here's a sub i put together to get at the number of agents who have more than 2 clients:
Sub agent_subset(output_sheet As String, _
Input_sheet_name As String, _
email_col As Integer, _
vendor_count_col As Integer, _
client_count_col As Integer, _
modified_col As Integer, _
num_of_clients As Integer)
' get a list of all agents with 2 or more clients and put them into a sheet
Application.DisplayStatusBar = True
Dim sheet_rows As Long
sheet_rows = Worksheets(Input_sheet_name).Cells(rows.Count, 1).End(xlUp).Row
Dim email_range As Range ' range of agent emails
Dim client_count_range As Range ' range of client count
Dim vendor_count_range As Range ' range of vendor count
Dim modified_range As Range ' range of modified at
With Worksheets(Input_sheet_name)
Set email_range = .Range(.Cells(2, email_col), .Cells(sheet_rows, email_col))
Set client_count_range = .Range(.Cells(2, client_count_col), .Cells(sheet_rows, client_count_col))
Set vendor_count_range = .Range(.Cells(2, vendor_count_col), .Cells(sheet_rows, vendor_count_col))
Set modified_range = .Range(.Cells(2, modified_col), .Cells(sheet_rows, modified_col))
End With
Dim n As Long
Dim counter As Long
counter = 0
Dim modified_array() As String
For n = 2 To sheet_rows
If client_count_range(n, 1).Value > num_of_clients Then
counter = counter + 1
Worksheets(output_sheet).Cells(counter + 1, 1).Value = email_range(n, 1).Value
Worksheets(output_sheet).Cells(counter + 1, 2).Value = client_count_range(n, 1).Value
Worksheets(output_sheet).Cells(counter + 1, 3).Value = vendor_count_range(n, 1).Value
modified_array() = Split(modified_range(n, 1).Value, "T")
Worksheets(output_sheet).Cells(counter + 1, 4).Value = modified_array(0)
End If
Application.StatusBar = "Loop status: " & n & "of " & sheet_rows
Next n
Worksheets(output_sheet).Cells(counter + 3, 1).Value = "Last run was " & Now()
Application.StatusBar = False
End Sub
It works great, but now I want to get a an even smaller subset of agents and clients based on other criteria. So, I'm going to write a similar function, manipulating similar data. My gut tells me using classes will make my life easier, but I don't know how to chop up the tasks.
Should there be an Agent class that has all the info about agents? and/or a client class? Or, should the classes be for looking at entire ranges or sheets?
I'm not looking for specific code, but a methodology on how to break things down.
I have to deal with large ranges in multiple sheets
If you think in terms of computers, you're code will be very functional. Those ranges represent something real (an agent, a customer, an invoice, a transaction), so think in those terms.
I would have an Agent class that held all the properties of an agent. I would have an Agents collection class that held all my Agent classes. Then, in my Agents class, I would have Filter methods that return subsets of the Agents class.
Here's an example: I have customers. Customers can be Active or not. Customers also have a template that I use when I email them certain information. When I want to email active customers who use the Table1 template, it looks like this
Set clsCustomersToEmail = clsCustomers.FilterOnActive(True).FilterOnTemplate("Table1")
For Each clsCustomer in clsCustomersToEmail
'Do stuff
Next clsCustomer`
In my CCustomers collection class, I have a couple of properties that return a CCustomers class with few customers than the big CCustomers class (called clsCustomers)
Public Property Get FilterOnActive() As CCustomers
Dim clsReturn As CCustomers
Dim clsCustomer As CCustomer
Set clsReturn = New CCustomers
For Each clsCustomer In Me
If clsCustomer.Active Then
clsReturn.Add clsCustomer
End If
Next clsCustomer
Set FilterOnActive = clsReturn
End Property
Public Property Get FilterOnTemplate(ByVal sTemplate As String) As CCustomers
Dim clsReturn As CCustomers
Dim clsCustomer As CCustomer
Set clsReturn = New CCustomers
For Each clsCustomer In Me
If clsCustomer.Template.TemplateName = sTemplate Then
clsReturn.Add clsCustomer
End If
Next clsCustomer
Set FilterOnTemplate = clsReturn
End Property
When I want to do stuff like write a bunch of customer data to a range, I make a property that returns an array, and write the array to the range.
Set clsCustomersPastDue = clsCustomers.FilterOnActive(True).FilterOnPastDue(True)
vaWrite = clsCsutomerPastDue.AgingReport
rCell.Resize(UBound(vaWrite,1),UBound(vaWrite,2)).Value = vaWrite
I tend to think of what physical things am I coding. They don't have to be tangible things, but if you can take it back to something that's tangible, that can be helpful.
A transaction is a thing. But if that transaction is an invoice, now determine the properties of that object become easy. For one, you can just look at a paper invoice and see what the properties are.
The next level is relationships. Every Agent class has customers. So your Agent object should have a Customers property that returns a CCustomers class. Or if it's not structured that tightly in real life, maybe your CCustomers class has a FilterOnAgent property that returns the subset of customers you're looking for.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.