| Steve Jorgensen 2004-09-23, 3:56 am |
| I've started doing a lot of a new pattern that I've found mind bogglingly
useful, and I was wondering if anyone else is doing something like it, and if
there's a name for it. I don't know if this would qualify as a "design
pattern" or not, but anyway...
Of course, back when I had no idea what I was doing, I wrote code loke lots of
beginners write - multi-page long procedures. Later, as I learned more about
code structure, I started writing small procedures, but the code was still
hard to manage because I simply turned what would have been one long procedure
into one deeply nested call tree, sort of like...
A
B
C
D
E
F
G
H
I
J
....
When I started doing TDD, I realized that this structure is not only hard to
debug, it's hard to write good tests for. Since then, what I've come up with
is to try to strike a balance between the monolithic function and the deeply
nested calling heirarchy, but I had to figure out a good pattern for how to do
that.
The trick I came up with is to change a stricture like this...
A
B
C
Into ...
m = C
n = B(m)
o = C(n)
It's sort of like functional programming, but using stored byproducts instead
of lazy-evaluated functions.
So, in Access/VBA (don't laugh please), say I want to set the value of the
textbox controls with names ending in "Foo" to 123. Using my old style, I
would have had an outer loop that goes through the list of controls, within
that, uses an If statement to see if it's a Textbox, then because the nesting
is getting deep, calls another function to set its value to Null if its name
ends in "Foo".
Using my new style, it now looks something like the code below. Yes, I know
if this were a Functional language, or I had some kind of Functor object, I
could eliminate duplicating the For Each loops in ControlsOfType and
ControlsNamedLike, ... It's actually more lines of code than the old way
right now, but most of the code is more reusable.
Advantages:
1. Alternative to monolithic, mile-deep nested control structures or mile-deep
call stacks of tightly coupled, special-purpose procedures.
2. Procedures are very loosely coupled.
3. Procedures are more atomic, general-purpose and reusable.
4. Procedures are easier to test in isolation.
5. Order of operations can be eaily changed.
Code example:
Public Sub FooControlsTo123()
Dim Textboxes As VBA.Collection
Dim FooTextboxes As VBA.Collection
Set Textboxes = ControlsOfType(Me.Controls, acTextBox)
Set FooTextboxes = ControlsNamedLike(Textboxes, "*Foo")
SetControlsValue FooTextboxes, 123
End Sub
Private Function ControlsOfType( _
InControls As Variant, _
ControlType As AcControlType _
) As VBA.Collection
Dim ctlItem As Access.Control
Dim colResult As New VBA.Collection
For Each ctlItem In InControls
If ctlItem.ControlType = ControlType Then
colResult.Add ctlItem
End If
Next
Set ControlsOfType = colResult
End Function
Private Function ControlsNamedLike( _
InControls As Variant, _
NamedLike As String _
) As VBA.Collection
Dim ctlItem As Access.Control
Dim colResult As New VBA.Collection
For Each ctlItem In InControls
If ctlItem.Name Like NamedLike Then
colResult.Add ctlItem
End If
Next
Set ControlsNamedLike = colResult
End Function
Private Sub SetControlsValue( _
ControlsToSet As Variant, _
SetToValue As Variant _
)
Dim ctlItem As Access.Control
Dim colResult As New VBA.Collection
For Each ctlItem In ControlsToSet
ctlItem.Value = SetToValue
Next
End Sub
|