You already know a lot about methods. Here are, however, a few more interesting details that you should be aware of concerning how methods can be used within a class module.
Saving results for subsequent calls
Let’s say that you have a function that returns a complex value—for example, the grand total of an invoice—and you don’t want to reevaluate it each time the client code makes a request. On the other hand, you don’t want to store it somewhere and run the risk that its value becomes obsolete because some other property of the invoice changes. This is similar to the decision that a database developer has to make: Is it better to create a GrandTotal field that contains the actual value (thus putting the consistency of the database at stake and also wasting some disk space) or to evaluate the total each time you need it (thus wasting CPU time each time you do it)?
Class modules offer a simple and viable alternative that applies equally well to all dependent values, be they implemented as functions or read-only properties. As an example, reconsider the ReverseName function in the CPerson class, and pretend that it takes a lot of processing time to evaluate its result. Here’s how you can modify this function to keep the overhead to a minimum without modifying the interface that the class exposes to the outside. (Added statements are in boldface.)
‘ A private member variable
Private m_ReverseName As Variant
Property Let FirstName(ByVal newValue As String)
‘ Raise an error if an invalid assignment is attempted.
If newValue = "" Then Err.Raise 5 ‘ Invalid procedure argument
‘ Else store in the Private member variable.
m_FirstName = newValue
m_ReverseName = Empty
End Property
Property Let LastName(ByVal newValue As String)
‘ Raise an error if an invalid assignment is attempted.
If newValue = "" Then Err.Raise 5 ‘ Invalid procedure argument
‘ Else store in the Private member variable.
m_LastName = newValue
m_ReverseName = Empty
End Property
Function ReverseName() As String
If IsEmpty(m_ReverseName) Then
m_ReverseName = LastName & ", " & FirstName
End If
ReverseName = m_ReverseName
End Function
In other words, you store the return value in a Private Variant variable before returning to the client and reuse that value if possible in all subsequent calls. The trick works because each time either FirstName or LastName (the independent properties) are assigned a new value, the Private variable is cleared, which forces it to be reevaluated the next time the ReverseName function is invoked. Examine this simple client code and try to figure out how difficult it would have been to implement equivalent logic using other techniques:
‘ This line takes some microseconds the first time it is executed.
If pers.ReverseName <> "Smith, John" Then
‘ If this line is executed, it internally resets m_ReverseName.
pers.FirstName = "Robert"
End If
‘ In all cases, the next statement will be as fast as possible.
Print pers.ReverseName
Of course, we might have also reevaluated the m_ReverseName value right in the Property Let procedures of FirstName and LastName, but that would undermine our main purpose, which is to avoid unnecessary overhead or postpone it as long as possible. In a real-world application, this difference might involve unnecessarily opening a database, reestablishing a remote connection, and so on, so it’s apparent that the advantages of this technique shouldn’t be underestimated.
Saturday, December 26, 2009
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment