Might Be Patterns

last modified: September 23, 2004

This is a place to list rough ideas that might be patterns in the hopes that knowledgeable visitors will help out with the following tasks:


Proposed patternoid from SteveJorgensen - Proposed name: "Replace Arrow with Result Forwarding".

Say you have something like this Access VBA code.

Public Sub SetFooTo123()
    Dim ctl As Access.Control
    For Each ctl in Me.Controls
        If ctl.ControlType = acTextbox Then
            If ctl.Name Like "*Foo" Then
                ctl.Value = 123
            End If
        End If
    Next
End Sub

This is the ArrowAntiPattern. We could get rid of the arrow using ExtractMethod, but this leads to tightly-coupled, special-purpose procedures.

My idea is that, instead, we flatten the arrow by creating a series of procedure calls, each of which produces a byproduct that is passed to the next, as below. Refactoring is done from the outside in, like peeling an onion. There is, for now, a bit more code here than when we started, but it's mostly more general-purpose code and much less tightly coupled.

It is now possible to test each component atomically, rather than testing all at once, or testing C, then B -> C, then A -> B -> C. Also, it is now trivial to change the order of operations. Note that this is starting to resemble what one might do in a Functional programming language, but without the lazy evaluation. Note that VBA has on Continue statement for loops, so we can't flatten the mini-arrows that way. Of course, if we then implement some sort of Functors, we could get rid of the duplicated ForEach loops, and if we extract a class for filtering and manipulating Controls collections, we could probably get rid of all the objControls passing, but those are other refactorings.

Public Sub SetFooTo123()
    Dim ctl As Access.Control
    Dim objControls As Object

    Set objControls = Me.Controls
    Set objControls = ControlsOfType(objControls, acTextBox)
    Set objControls = ControlsNamedLike(objControls, "*Foo")
    SetValueOfControls objControls, 123

End Sub

Private Function ControlsOfType( _
    InControls As Variant, _
    ControlType As AcControlType _
) As VBA.Collection
    Dim ctl As Access.Control
    Dim colResult As New VBA.Collection

    For Each ctl In InControls
        If ctl.ControlType = ControlType Then
            colResult.Add ctl
        End If
    Next

    Set ControlsOfType = colResult
End Function

Private Function ControlsNamedLike( _
    InControls As Variant, _
    NamedLike As String _
) As VBA.Collection
    Dim ctl As Access.Control
    Dim colResult As New VBA.Collection

    For Each ctl In InControls
        If ctl.Name Like NamedLike Then
            colResult.Add ctl
        End If
    Next

    Set ControlsNamedLike = colResult
End Function

Private Sub SetValueOfControls( _
    Controls As Variant, _
    NewValue As Variant _
)
    Dim ctl As Access.Control

    For Each ctl In Controls
        ctl.Value = NewValue
    Next

End Sub

Loading...