Session E-STRU

Advanced Object Oriented Design Patterns in Visual FoxPro

Steven Black
SBC


Summary

This session, aimed at intermediate and advanced level developers, builds on the introductory patterns session. We’ll examine a variety of design patterns particularly useful for making systems adaptable.

Pattern: Strategy

The Strategy design pattern permits attaching an appropriate behavior or algorithm at run-time. It helps keep behavior flexible by decoupling a process from the one or more potential behaviors (or algorithms) that implement it. Each encapsulated behavior becomes a strategy.

Intent

Some processes require variety in behavior. To achieve behavior variety with a minimum of fuss, it helps to package the behaviors in classes of a common type - thus making them interchangeable - and thereafter tinker only with the behavior classes, independently of the process that invokes them.

Motivation

Sometimes the only difference between two classes is their behavior. It’s not what the objects are that’s different, but rather what they do. Subclassing a process for each new behavior is usually a workable methodology. Another way, usually better, is to subclass only the variant parts of processes, and thereafter tinker only with those.

For example, an accounting system produces invoices for companies operating in many different tax jurisdictions. Tax calculations vary depending on the jurisdictions (and intra-jurisdictional agreements) where sellers and customers are located. Taxes can also vary according to what is being invoiced; children’s clothes, books, liquor, tobacco, and heating oil are examples of products that get special (and different) tax treatment everywhere.

Similarly, in some situations, discounts are popular sales incentives. Sales managers are constantly inventing creative new discount schemes. Sometimes discount creativity is constrained by the accounting software’s ability to define and handle them.

Do you really want to deal with the potential for a separate industry or client-specific invoicing subclass for each country, state, or sales territory where your application is used? Of course not. You need a rational way to build your invoicing module so new features can be applied without polluting the underlying foundation which is otherwise largely invariant.

Setting up a Strategy Pattern

A Strategy pattern decouples a process from the algorithms that implement it. The key to setting up a successful Strategy pattern is interface consistency: give all your strategies a common interface, and the invocation process won’t care which class provides the services. The easiest way to give strategies a common interface is to make all the strategies belong to the same class.

Figure 1. Separating a process from its variable behaviors (Strategies) is easier if the interface defining the behaviors is consistent, and the best way to achieve this is by consolidating the strategies into the same class.

In the diagram in Figure 1, the Process "owns" a separate and independent Strategy instance that has an interface defined in the AbstractStrategy class. This ownership means, in practice, that the strategy objects are scoped within the Process. A common variant is for the Process to own more than one Strategy instance. Strategy objects can, of course, be instantiated as needed, and perhaps thereafter retained in case they're needed again. This "pay-as-you-go" behavior is nice.

Applicability

Here are some generally applicable reasons to consider a Strategy pattern:

Visual FoxPro Example

Everywhere I go, customers have creative ideas about how discounts should work, or how they should be presented. (Henceforth we’ll only talk about discounts, but everything here applies also to processing taxes).

Say your invoice class currently has the following interface:

DEFINE CLASS Invoice AS Document && Baseclass Custom
FUNCTION CalcPrices()
FUNCTION CalcDiscounts()
FUNCTION Print()
ENDDEFINE

Now suppose a client requires a new sort of discount, a significant variant. What to do? Here are a few options:

  1. Add a CASE statement to CalcDiscounts() to handle the new discount. This works of course but, at the limit, giant CASE statements don’t scale or maintain very well.
  2. Subclass the whole invoice class and override the CalcDiscount() method. This is probably workable, but it isn’t pretty if you consider that discounts is just one among many factors (forces) that can trigger thoughts of subclassing an invoicing class.
  3. Create a separate class whose function is solely to calculate discounts, and attach an instance of this class (or one of its subclasses) as required. This scenario is what Strategies are all about.

Here are three simple discount strategy classes. The first calculates a discount for each line item. The second calculates a discount based on a threshold invoice total, and the third calculates discounts for certain product types. All three are subclasses of an abstract discount type. These are just code skeletons, but from this it’s easy to see that the AbstractDiscount class defines the whole class interface. It doesn’t have to – you can modify the interface of subclasses to suit your mood – this is simply the way I prefer to do things.

DEFINE CLASS AbstractDiscount AS Custom
*-- Define the inerface for all discounts
Rate = 0 && The discount rate
nThreshold= 99999999 && Minimum purchase
cType = "None" && Type constraint

FUNCTION Execute( toObject)
RETURN .F.
ENDDEFINE

DEFINE CLASS LineItemDiscount AS AbstractDiscount
Rate= 0.1
FUNCTION Execute( toInvoice)
*-- Apply a discount to each line item
LOCAL lni
FOR lni= 1 TO ALEN(toInvoice.LineItems,1)
toInvoice.LineItem( lni).Discount = THIS.Rate * ;
toInvoice.LineItem( lni).Price
ENDFOR
ENDDEFINE

DEFINE CLASS LineItemDiscount AS AbstractDiscount
nThreshold= 1000
FUNCTION Execute( toInvoice)
*-- Apply a discount if the total exceeds a threshold
LOCAL lni, lnTotal
lnTotal = 0
FOR lni= 1 TO ALEN(toInvoice.LineItems,1)
lnTotal=lnTotal + toInvoice.LineItem( lni).Price
ENDFOR
IF lnTotal >= THIS.lnThreshold
toInvoice.Discount= lnTotal* THIS.rate
ENDIF
ENDDEFINE

DEFINE CLASS ProductTypeDiscount AS AbstractDiscount
nRate= 0.1
nThreshold= 1000
cType= "Dog Food" && But not hard-wired, obviously

FUNCTION Execute( toInvoice)
*-- Apply a discount to each qualifying line item
LOCAL lni
FOR lni= 1 TO ALEN(toInvoice.LineItems,1)
IF toInvoice.LineItem( lni).cType= THIS.cType
toInvoice.LineItem( lni).Discount = THIS.Rate * ;
toInvoice.LineItem( lni).Price
ENDIF
ENDFOR
ENDDEFINE

Some Downsides

Classes that cooperate as in a Strategy pattern are certainly flexible, but separating algorithms into independent classes can incur significant disadvantages. The most onerous I’ve found occurs when the strategy class needs non-trivial access to data structures in the calling process. For example, the strategy classes may need to know alias names, or need to share arrays and pointers, all owned by the invoking process. In this situation, I’ve usually found it best to use a separate object to package everything about the calling process that the strategy may require. In other words, instead of passing 36 parameters to strategy objects, pass a single object having 36 properties. This keeps the interface clean – we pass at most one parameter, an object – and makes it easier to reuse processes and strategies as generalized abstractions.

Pattern: Decorator

A decorator wrapper (I'll just call it Decorator) is an elegant OOP technique that can be handy in a wide variety of situations. In particular, the Decorator pattern is useful for extending the functionality of a class without polluting (or even needing) the original source.

Subclassing isn't always cool

But before we get to the decorator pattern, lets examine what happens when we allow a class to grow organically with inheritance. To illustrate, consider the following class interface for a frog:

DEFINE CLASS Frog AS CUSTOM
FUNCTION Jump(nValue)
FUNCTION Eat()
ENDDEFINE

Amphibians are easily created with Visual FoxPro. Suppose that we needed to create a new sort of frog, one that can dance. We could subclass Frog as follows:

DEFINE CLASS DancingFrog AS Frog
FUNCTION Dance()
ENDDEFINE

Suppose we later need a singing Frog. Well, within our current simple hierarchy, we already have several obvious options.

So, buffeted by the needs of this current implementation, you make your choice and you take your chances. What if you later needed a burping frog, one that belches after meals. Do we subclass again? If so, where? Do we add a Burp() method, or do we simply augment the Eat() method because problem analysis indicates that burping naturally follows from eating. Again, which hierarchical level is best for modification? And later, when you need a frog that can beg, roll-over, shake-a-leg, and stay, a new question eventually arises: "How did this Frog class become such a mess?".

At the outset, a pragmatic reuse artist would be correct in asking when, if ever, will the need for a singing, dancing, and belching frog ever arise again? Why not just augment the frog for this instance, without polluting our general, simple, and reusable Frog class?

The Decorator alternative

The answer may be to use a decorator. A decorator is, in essence, a class with mostly "pass-through" behavior. It "wraps" a class by reference, forwarding all messages to the reference except for the messages the wrapper is designed to intercept. Setting up a decorator takes a bit of work, but thereafter it's a snap to use. Consider the following DecoFrog class:

DEFINE CLASS DecoFrog AS CUSTOM
oRealFrog= .NULL.
FUNCTION INIT( oFrog)
THIS.oRealFrog= oFrog
FUNCTION Jump(n)
THIS.oRealFrog.Jump(n)
FUNCTION Eat()
THIS.oRealFrog.Eat()
ENDDEFINE

Sample 4. Notice the key element of decorators: They are "transparent", passing through all messages except for those that need to be intercepted. Creating an abstract decorator class (like the one above) that passes through everything is the first step. Now to augment the frog for a particular instance, we can use a simple subclass of the decorator without polluting the Frog class.

To the outside world, the DecoFrog class has the same programming interface as a Frog. But it's not a Frog, it's a lens through which we can "see" a Frog. If we need a specialized one-off Frog, like one that sings, we could do this:

DEFINE CLASS SingingFrog AS DecoFrog
FUNCTION Sing()
? WAIT WINDOW "It's not easy being green..."
ENDDEFINE

Similarly, we can define a dancing frog by simply subclassing the class DecoFrog as follows:

DEFINE CLASS DancingFrog AS DecoFrog
FUNCTION Dance()
DecoFrog::Jump(+1)
DecoFrog::Jump(-2)
DecoFrog::Jump(+1)
ENDDEFINE

Retrofitting a decorator is easy. Where before your code looked like this:

Kermit=CREATE( "Frog")

A singing frog can now be substituted at run-time like this:

Kermit=CREATE("Frog")
Kermit=CREATE("SingingFrog",Kermit)

or more succinctly:

Kermit=CREATE("SingingFrog",CREATE("Frog"))

(Note that nesting CREATEOBJECT statements works just fine in Visual FoxPro – Version 3. In VFP version 5.0, nesting CREATE() statements is unstable, don't do it.)

Additionally, decorators can be chained, with functionality added or modified as needed! This gives you considerable pay-as-you-go flexibility. For example, to build a singing and dancing frog, do as follows:

Kermit=CREATE("Frog")
Kermit=CREATE("SingingFrog",Kermit)
Kermit=CREATE("DancingFrog",Kermit)

or, if you prefer one-line of code:

Kermit=CREATE("DancingFrog", ;
CREATE("SingingFrog",CREATE("Frog")))

Which creates an object relationship illustrated by the following object diagram:

Figure 2. Two decorators chained together, both augmenting the object.

Well, Tada! We now have an ordinary Frog named Kermit that appears, in this instance, with the ability to sing and dance, and we didn't need to pollute the Frog class to get it. In fact, we didn't need the source to class Frog.

Decorator Benefits

Here are some benefits that come from using decorators.

Decorator Downsides

As with all things, the "no free lunch" pattern applies: You cannot get the added flexibility afforded by using a decorator without some tradeoffs. Here are some of them:

Figure 3. One of the difficulties of managing a Decorator is maintaining its interface in sync with the objects to be decorated. Problems can be greatly alleviated by making the decorator a subclass of an available abstract class, one whose sole purpose is (by definition) to define the class interface.

Pattern: Proxy

Provide a surrogate or placeholder for another object to control access to it. Proxies are usually decorators in everything but name.

Problem

How to provide correct and/or efficient access to an object that may be resource intensive or otherwise require protection?

Context

A client needs the services of an object, but direct access is technically possible but questionable.

Forces

Solution

Make a component’s clients communicate with a representative rather than with the component itself.

Resulting Context

Three actors: The client (as usual), the original object (as usual), and an intervening object (the Proxy) which serves as a placeholder for the original object and forwards requests as appropriate.

Uses for the Proxy pattern

There are many uses for the Proxy pattern.

Of course, you could combine two or more of the above roles.

Pattern: Template Method

A template method is an abstract algorithm that references other methods. Template methods define the specific steps in an algorithm, often without much regard for implementation details. For example, the following method, used in military software to land jets on aircraft carriers on foggy nights, is an algorithm that directly calls four other methods:

PROCEDURE Carrier_Landing
THIS.Locate_Carrier()
THIS.Line_Up()
THIS.Final_Approach()
THIS.Hit_The_Deck()
ENDPROC

This is exciting stuff. Forgive me, please, for not testing this.

The methods invoked by template methods are called hooks. Hook methods are places where adaptation can occur by subclassing. It’s the job of hooks (and especially hook subclasses) to define, augment, or override each step in the algorithm. Hook methods are not to be confused with hook operations, which are defined in the next pattern. Hook operations are places, back-doors if you will, where external programs may be explicitly called to augment or override an existing method without subclassing.

The Template Method pattern, which is the interaction between template methods and hooks, is found in, among other places, all patterns that deal with abstract classes and abstract methods.

Intent

Codify the structure of an algorithm in a method, but purposefully leave the implementation steps to other methods, thereby making the algorithm partially abstract (or as abstract as it should be).

Motivation

As a general rule, the steps in most software processes are known, as is their sequencing. For example, we authenticate users before giving them access to sensitive data; our programs clean-up before termination; we locate the runway before we begin our final approach; and so on.

In higher level abstractions, however, that’s often all we know. We know that our programs should clean-up before termination, but exactly what this cleanup means — and exactly how it will be done — isn’t of immediate high-level concern. More importantly, how the program cleans-up probably should be flexible so it can be done correctly under different circumstances.

A class’s ability to adequately adapt is a virtue. Template methods are designed with exactly this in mind.

Structure

A good way to think of the Template Method pattern are template methods corresponding to a "frozen" (invariable) part of a framework. The template methods call "hot spots" (hooks), which are domains that are purposefully adaptable.

Figure 4. This diagram illustrates a central theme of the Template Method pattern, namely that variable elements are kept distinct in the interest of easier subclassibility.

Visual FoxPro Example

Template Method patterns are among the easiest to understand and use, and they can be found everywhere. Anyone with top-down design experience will quickly recognize an instance of the Template Method design pattern.

Consider the following task: You must write a Visual FoxPro behavior class to direct a robot to search for contraband and explosives. It’s execute method might look like this.

DEFINE CLASS RobotBehavior AS CUSTOM
FUNCTION Execute() && This is our Template method
THIS.Ingress()
THIS.Search()
THIS.Egress()
THIS.GoSomewhereSafe()
THIS.SetWaitForInstructions()
ENDFUNC
FUNCTION Ingress()
*-- Subclass and define your own behavior.
*-- Note that it isn’t unusual for template
*-- methods to call other template methods.
*-- Example, THIS.Ingress() could be another
*-- template method, like this:
*
* THIS.ApproachRamp()
* THIS.NavigateRamp()
* THIS.EnterAirPlane()
*
ENDFUNC

FUNCTION Search()
ENDFUNC

FUNCTION Egress()
ENDFUNC

FUNCTION GoSomewhereSafe()
ENDFUNC

FUNCTION SetWaitForInstructions()
ENDFUNC

ENDDEFINE

Listing 1 , illustrating a template method called ::Execute(), which calls five hooks. You would subclass this class to provide different implementation behavior.

I’m constantly amazed at how easy it is to write complex real-time robot control systems in Visual FoxPro.

In the example above, the template method is the Execute() method. In and of itself, the method (and hence the class) is completely useless — in spite of its ambitious intent, it does nothing. What it provides, however, is an abstract basis for the development of specialized subclasses which can make robots to search cars, buses, airplanes, embassies, even your own home.

What to Expect From Template Method Patterns

On balance, classes built with template methods are easily adapted by subclassing because the major steps of an algorithm and their interfaces are pre-defined. All we need to do is subclass, and provide our own behavior where appropriate.

If you use VFP version 5.0, you have a fair degree of control over what downstream users can and cannot do. For example, by using the new Hidden methods and properties features, you can limit what the user’s classes can see and accomplish with subclasses, or force them to use access methods to access class services to make the class more robust.

A real downside to Template Methods is that you must know which methods have default behavior that may be overridden, and which ones have no default behavior, meaning they must be overridden.

Pattern: Hook Operations

Author’s note: I would like to emphasize the contribution of Wolfgang Pree’s work in the foundation of many ideas discussed in this pattern (see References below).

Hook operations are places within procedural or method code where adaptation is specifically designed to take place. The Hook Operations design pattern provides a consistent interface or methodology for adapting software using hooks. Hook operations usually do nothing by default; their invocation is the exception, not the rule. Correctly implemented, hook operations allow almost limitless extensibility.

Intent

Explicitly provide places where your software can be extended using a consistent extension mechanism, document the interface, and permit downstream developers to customize to suit their needs.

Motivation

Object oriented toolkits and frameworks are composed of related and reusable classes that give general-purpose functionality. Toolkits provide code reuse, while frameworks provide architectural reuse. In both cases, flexibility and extensibility are a virtue.

There are several ways that toolkits and frameworks can be adapted, the most obvious is to subclass and then augment, or override, the original behavior. Subclassing pre-supposes several things that usually cannot be guaranteed: Firstly, to subclass, source code is required. Secondly, subclassing requires specialized knowledge of the classes and understanding of their functional interactions; certainly some subclassing tasks are trivial, but many are not. Third, it’s extremely difficult to know every process that creates the parent class of this new subclass, and you may need to doctor these processes appropriately or some instances won’t behave as you expect.

Hook operations are an alternative to all this. Hook operations are well defined back-doors where folks can attach programs to modify, augment, wrap, or replace the invoking process.

As a quick aside, we need look no further than Visual FoxPro’s own architecture for a fine example of hook behavior. All of FoxPro’s programmable events, for example, fire before the actual native VFP behavior. The code you put in, say, a control’s Click() event, executes before the actual Windows click message, and using NODEFAULT you can instruct VFP not to fire its native behavior. So when you write event code, you are in fact hooking an instance of VFP’s base classes and augmenting or overriding the native behavior.

Another example is the Visual FoxPro Class Browser, which is a real hookfest. By using its AddIn() method, and by specifying a method to hook, you can permanently register custom behavior for a variety of events. Registering the add-in is persistent because the AddIn() method creates a record in BROWSER.DBF, which lives in your HOME() directory.

For example, with the registration instructions and the code below, you can hook the Browser’s ExportClass() method to change the content of the exported class code to make it hog less space. The resulting code contains spaces instead of tabs (which I personally prefer), and also eliminates all the blank lines that are otherwise generated. This is very handy if you need to cut and paste code in a limited-width electronic message.

This particular add-in places the modified class code in the Windows clipboard. As far as I know, there is no way to hook the ExportClass() method just before it fills the class code display window. We’ll call this add-in on the CmdExport.Click() hook, fill the clipboard, modify the clipboard contents, and then return to the regular export process. Our modified code in the clipboard, not in the Class Browser’s code window.

*-- NoHog.PRG
*-- Browser Addin to capture the class browser's
*-- exported class code and make it hog less space.
*--
*-- Note: The modified code is placed on the
*-- clipboard; the code in Browser’s code
*-- display window is unchanged.
*--
*-- To register, invoke BROWSER, then in the command
*-- window:
*-- _oBrowser.Addin( "NoHog", "cmdExport.Click", ;
*-- "NoHog.PRG")

*-- Browser Add-Ins pass a reference to Browser
LPARAMETER oBrowser

*-- Put the class definition on the clipboard
*-- Note: The .F. parameter on ExportClass() supresses
*-- the class code display window. Here we just want
*-- to place the code on the clipboard. The code display
*-- window will appear naturally as part of the
*-- downstream behavior which executes after this add-in.
_CLIPTEXT= oBrowser.ExportClass(.F.)

*-- Tabs, begone! I prefer two spaces instead.
_CLIPTEXT=STRTRAN(_CLIPTEXT, chr(9), SPACE(2))
*-- Excess blank lines, begone!
DO AT( CHR(13)+CHR(13), _CLIPTEXT) > 0
_CLIPTEXT=STRTRAN(_CLIPTEXT, CHR(13)+CHR(13), CHR(13))
ENDDO

*-- Returning .F. tells BROWSER to execute its regular
*-- cmdExport.Click() method as usual (which displays
*-- the standard results in a class code display
*-- window, wasteful of white space as always.
*-- Remember that your modified stuff is in the
*-- clipboard.
RETURN .F.

Listing 2: A Class Browser hook to send reformatted source code to the clipbpard.

Visual FoxPro Example

Here is a neat way to implement hook operations: Define a custom property to hold reference to a hook object, and thereafter always call this hook object before you execute your standard processes.

To implement a Hook Operation pattern you need 1) to code the hook operation in your base class methods, and
2) design and maintain hook classes.

Here’s the stripped-out core of a hook operation, without much regard for anything but the essentials. In real life, you might use PEMSTATUS() to check the existence of the hook method, as well as check the TYPE() of the hook itself. I’ve done this elsewhere, but not here, the interest is clarity.

DEFINE CLASS SomeSubclass AS SomeClass
*-- This is the hook reference
oHook= .NULL.
FUNCTION SomeMethod( txPassed)
*-- Here is a raw hook call
IF ! ISNULL( THIS.oHook)
THIS.oHook.SomeMethod( txPassed)
ENDIF
* << YOUR SomeMethod( ) CODE HERE >>
ENDDEFINE

Listing 3, a simple hook operation, called early in ::SomeMethod()

Here are some facts about the example above:

Listing 4, a simple hook operation, called early in ::SomeMethod(), that overrides the remainder of ::SomeMethod() with a return value.

Now we can override our default behavior by agreeing that an "override" hook returns logical false. This is not the best solution, obviously, because the convention that "override hooks return false" really isn’t sustainable. All sorts of reasons exist for a method to return logical false; using this protocol to manage the behavior of all your hooks, forever, is odious.

A solution I prefer is a sneaky use of a persistent and unused legacy FoxPro system memory variable to set a flag, as follows:

DEFINE CLASS SomeSubclass AS SomeClass
*-- This is the hook reference
oHook= .NULL.
FUNCTION SomeMethod( txPassed)
*-- Here is a hook call that can override our code
IF ! ISNULL( THIS.oHook)
THIS.oHook.SomeMethod( txPassed)
*-- In this example, hooks use the unused but
*-- available _BOX system memory variable to
*-- communicate an intended NODEFAULT.
*-- So in hook code, _BOX=.F. means NODEFAULT

IF ! _BOX
*-- Reset _BOX for the benefit of the next hook
*-- that may need it.
_BOX= .T.
*-- "NODEFAULT", so we’re done.
RETURN
ENDIF
ENDIF
* << YOUR CODE HERE >>
ENDFUNC
ENDDEFINE

Listing 5, a simple hook operation, called early in ::SomeMethod(), that overrides the remainder of ::SomeMethod() by setting a handy, public, and otherwise unused flag.

The help file says that _BOX system memory variable is "Included for backward compatibility. Use the Report Designer instead". Well, I say: use it for hooks to communicate to their calling methods instead. Voila. Now it doesn’t matter what hook methods return; if they set _BOX to .F., that means, in effect, NODEFAULT.

Here is a more illustrative example of the benefits of hooks. Here we’ll hook the RightClick() method of a textbox to provide a context sensitive popup menu. In practice you could hook all the common methods of all your base classes to do a variety of things.

The class definition, complete with its seeded RightClick() method, looks like this:

***************************************************
*-- Class: appTextbox
*-- BaseClass: Textbox
DEFINE CLASS appTextbox AS Textbox

*-- Reference to a hook object
ohook = .NULL.

PROCEDURE RightClick
*-- Delegate to any hook
IF ! ISNULL( THIS.oHook) AND ;
TYPE( "THIS.oHook") = "O" AND ;
PEMSTATUS( THIS.oHook, "RightClick", 5)
_BOX= .T.
THIS.oHook.Rightclick()
IF ! _BOX
RETURN
ENDIF
ENDIF
ENDPROC

FUNCTION Release
*-- It’s always wise to clean up your pointers
THIS.oHook= .NULL.
RELEASE THIS
ENDDEFINE

Listing 6, a textbox with a RightClick hook.

Here’s a RightClick()-seeded hook object that works extremely well with textboxes and edit boxes to bring up a handy edit menu:

DEFINE CLASS lblmousehook AS label
Caption= "MouseHook"
Name = "mousehook"

PROCEDURE RightClick
*-- Bring up a handy edit tools menu
DEFINE POPUP shortcut SHORTCUT RELATIVE FROM MROW(),MCOL()
*-- Cut
DEFINE BAR _med_cut OF shortcut PROMPT "Cu\<t" ;
KEY CTRL+X, "Ctrl+X" ;
MESSAGE "Removes the selection and places it onto the Clipboard"
*-- Copy
DEFINE BAR _med_copy OF shortcut PROMPT "\<Copy" ;
KEY CTRL+C, "Ctrl+C" ;
MESSAGE "Copies the selection onto the Clipboard"
*-- Paste
DEFINE BAR _med_paste OF shortcut PROMPT "\<Paste" ;
KEY CTRL+V, "Ctrl+V" ;
MESSAGE "Pastes the contents of the Clipboard"
*-- Select All
DEFINE BAR _med_slcta OF shortcut PROMPT "Se\<lect All" ;
KEY CTRL+A, "Ctrl+A" ;
MESSAGE "Selects all text or items in the current window"
*-- Clear
DEFINE BAR _med_clear OF shortcut PROMPT "Cle\<ar" ;
MESSAGE "Removes the selection and does not place it onto the Clipboard"
ACTIVATE POPUP Shortcut
ENDDEFINE

Listing 7, a usable RightClick() hook usable with code in Listing 6.

To set up this basic hook do the following:

oForm= CREATE("MyForm")

oForm.AddObject( "oTxtbox", "appTextBox")
oForm.AddObject( "oMouseHook","lblMouseHook")
oForm.otxtbox.Visible= .T.
oForm.otxtbox.oHook= oForm.oMouseHook
oForm.Caption= "RightClick this textbox"
oForm.Show()
READ EVENTS

When you rightclick over the textbox, control is passed to the hook, which invokes a context sensitive shortcut menu. Two things to draw from this example:

Applicability

Two conflicting forces determine where and when hook operations should be used. On one hand, hook operations are most valuable at critical junctures in a process. On the other hand, if outsiders are those applying hooks, usability dictates that they should be positioned consistently at predictable junctures.

Unfortunately, it’s difficult to identify and document exactly where a process’ critical junctures lie – even assuming we could predict the needs of those who will apply hooks. For this reason, hook operations are usually found, predictably, either at the beginning or at the end of methods.

It’s not possible to have hook operations at both the beginning and the end of methods because of inheritance. When one executes a ParentClass::Method() call, executing both "pre" and "post" hooks at that single point isn’t likely desirable.

How, then, to provide hooks both at the beginning and at the end of a particular process? It’s easy if you use a multi-part process. For example, consider a commandbutton whose a Click() calls a particular method, as follows

DEFINE CLASS HooklessProcess AS CommandButton
FUNCTION CLICK
DO THISFORM.SomeMethod
ENDDEFINE

DEFINE CLASS MyForm AS FORM
ADD OBJECT oCmd AS HooklessProcess

FUNCTION Somemethod
WAIT WINDOW "No hooks here"
ENDDEFINE

Listing 8, a button without hooks.

Compare the above to this, where the "pre" hook is launched by the commandbutton, and the "post" hook is launched at the end of the method invoked.

DEFINE CLASS FullyHookedProcess AS CommandButton
FUNCTION CLICK
IF ! ISNULL( THIS.oHook)
THIS.oHook.Click && The "Pre" hook
ENDIF
THISFORM.SomeMethod()
ENDDEFINE

DEFINE CLASS MyForm AS FORM
ADD OBJECT oCmd AS StartHookLessProcess

FUNCTION Somemethod

* << Your code here >>

IF ! ISNULL( THIS.oHook)
THIS.oHook.SomeMethod() && The "Post" hook
ENDIF
ENDFUNC
ENDDEFINE

Listing 9, a button with a hook before calling a method, which contains a hook at its conclusion.

You can easily abstract this with the following rule of thumb: Events (like click and dblclick) always fire "pre" hooks, and Methods (things invoked by events) always fire "post" hooks. So you have, in effect, an invokable back-door on the way in, and another invokable back-door on the way out.

What to expect from Hook Operation patterns

Classes created with embedded hook operations are generally much more flexible than those that aren’t. If you define hook operations consistently and predictably throughout your application, then it’s usually possible to attach new behavior to satisfy the needs of a particular instance without subclassing. Moreover, hook operations can be reckoned and bound at run time.

Combining Templates and Hooks

Now let’s take these two patterns, combine them in a variety of ways, and see what we can come up with.

First, a quick summary:

Here are two new definitions that we’ll use from here onwards


A hook class is a class that contains at least one hook method. In the following diagrams we’ll represent hook classes like this:


Let’s look at some ways that these classes can be deployed.

Scenario 1: Template and Hook classes are one and the same


This configuration comes up all the time. It happens when hook methods are implemented by the template class itself. Obviously, in this case, none of the classes called by the template method can be abstract. This is simply the common case when the template class is fully satisfied within its object.

A self-sufficient template class can be subclassed for new hook behavior, which leads to the following common configuration. Everyone who’s programmed in an object oriented way has done this:

In other words, a self-sufficient class is subclassed and one or more hook methods is augmented or overridden to achieve a new, self-sufficient behavior. This is what everyone immediately thinks of when they hear a phrase containing the words "benefits of OOP".

Scenario 2: Template and Hook Classes are Separate

In this configuration, there is no inheritance relationship between the template classes and the hooks that implement them. Template T and hook H are coupled in the sense that T must know the interface of H. A change in H, or a requirement change in T, implies a change in the other in order to preserve correctness.

Managing the interfaces between the two classes is not trivial in the case where T is a template due to the presence of one or perhaps many hook operations. A logical way to manage hook operation interfaces is to use the same method name in the template method and the hook operation, as follows:

PROCEDURE RightClick
*-- Delegate to any hook – assumes hook possesses
*-- a method of the same name
IF ! ISNULL( THIS.oHook)

THIS.oHook.RightClick() && Same name as the
&& method of origin

ENDIF
ENDPROC

Listing 10, naming hook methods after its invoker makes abundant sense.

Which begs the question: If template classes and hook classes share the same interface, as in the example above, why would they come from separate classes?

In Visual FoxPro, all the base classes have some methods in common. For example, you can click, right click, and double click virtually all the visual classes, so it appears the separate-classes question has little relevance. It’s when you start propagating custom methods, however, that the question becomes increasingly appropriate as the dual-interface maintenance burden increases.

In summary, there may be merit to the idea that template and hook classes should belong to the same class hierarchy in order to make maintaining the interfaces a little easier, if not automatic.

On the other hand, if your template methods and hook operations don’t share the same interface nomenclature, then you have the makings of a perpetual maintenance nightmare, and there is little you can do at an architectural level to alleviate that. The best you can do is use a naming convention and hope you don’t forget to correctly map the interfaces together.

Scenario 3: Hooks inherit from Templates

At first glance, having hook classes inherit from template classes seems to make sense. If we define a new non-HIDDEN method in template T, then hook class H will possess it automatically. We’ll still need to add hook implementation code, of course, but in the interim at least the class interfaces are automatically in sync.

Unfortunately, from a purist OOP design perspective, this is completely bogus. Here’s why:

Scenario 4: Templates inherit from Hooks

This configuration is not intuitive and, at first glance, seems outlandish. Why would a template class inherit from a hook class? After all, T defines the basic algorithms, and usually you need to subclass T to implement its abstract hook methods, or to augment or override its concrete hook methods. This hardly seems worth talking about.

If we look at this configuration more closely, we can come to the following surprising (I think potentially explosive) conclusions.

Defining the hook methods in H, and making T a subclass of H, means

We’ll talk more about hook operations during the session.

x=CREATE("MyForm")
X.Show()
READ EVENTS

DEFINE CLASS AbstractHook AS Relation && Relations are Ultra Light!
**********************************************
* A chainable hook class
**********************************************

*-- This property, along with the SetHook method,
*-- allows us to chain hooks!
oHook= .NULL.

*-- Set the oHook reference
PROCEDURE setohook
LPARAMETERS txPassed
LOCAL llRetVal
DO CASE
CASE ISNULL( txPassed)
THIS.oHook= .NULL.
llRetVal= .T.

CASE TYPE( "txPassed")= "O"
IF TYPE( "THIS.oHook")= "O" AND ;
PEMSTATUS(THIS.oHook, "SetoHook", 5)

THIS.oHook.SetoHook( txPassed)
ELSE
THIS.oHook= txPassed
ENDIF
llRetVal= .T.
ENDCASE
RETURN llRetVal
ENDPROC

**********************************************
*-- Here we define just a two methods to hook.
*-- In practixe you'll want to hook many more
**********************************************

PROCEDURE GotFocus
*-- Delegate to the implementation chain
IF ! ISNULL( THIS.oHook) AND ;
TYPE( "THIS.oHook") = "O" AND ;
PEMSTATUS( THIS.oHook, "GotFocus", 5)

RETURN THIS.oHook.GotFocus()
ENDIF

PROCEDURE RightClick
*-- Delegate to the implementation chain
IF ! ISNULL( THIS.oHook) AND ;
TYPE( "THIS.oHook") = "O" AND ;
PEMSTATUS( THIS.oHook, "RightClick", 5)

RETURN THIS.oHook.Rightclick()
ENDIF

ENDDEFINE

DEFINE Class MyForm AS Form
AutoCenter= .T.
Caption= "Chained Hooks Example - 3 different behaviors"
ShowTips= .T.

ADD OBJECT txt1 AS MyTextBox WITH Left=9, Top=11
ADD OBJECT txt2 AS MyTextBox WITH Left=9, Top=41
ADD OBJECT txt3 AS MyTextBox WITH Left=9, Top=71

PROCEDURE Init

Local loHandle

*********************************
* First textbox gets help and edit features
*********************************
loHandle= CREATE("HelpRightClick")
THIS.txt1.SetoHook( loHandle)
loHandle= CREATE("EditRightClick")
THIS.txt1.SetoHook( loHandle)

*********************************
* Second textbox gets just edit features
*********************************
loHandle= CREATE("EditRightClick")
THIS.txt2.SetoHook( loHandle)

*********************************
* Third textbox gets random color and help features
*********************************
loHandle= CREATE("ColorRightClick")
THIS.txt3.SetoHook( loHandle)
loHandle= CREATE("HelpRightClick")
THIS.txt3.SetoHook( loHandle)

PROCEDURE Destroy
CLEAR EVENTS

ENDDEFINE

DEFINE CLASS ColorRightClick AS AbstractHook
*-- This class causes the screen backcolor
*-- to go random when the right click method fires.
nOldColor= 0

PROCEDURE INIT
THIS.nOldColor= _SCREEN.BackColor

PROCEDURE GotFocus
DODEFAULT()
IF POPUP("shortCut")
DEACTIVATE POPUP ShortCut
RELEASE POPUPS ShortCut
ENDIF

PROCEDURE RightClick
DODEFAULT()
_SCREEN.BackColor= RAND()* 255^3

PROCEDURE Destroy
_SCREEN.BackColor= THIS.nOldColor

ENDDEFINE

DEFINE CLASS HelpRightClick AS AbstractHook
PROCEDURE GotFocus
DODEFAULT()
IF POPUP("shortCut")
DEACTIVATE POPUP ShortCut
RELEASE POPUPS ShortCut
ENDIF

*-- This class adds Help to the shortcut menu
*-- when its rightclick method fires.
PROCEDURE RightClick
DODEFAULT()
IF ! POPUP("ShortCut")
DEFINE POPUP shortcut SHORTCUT RELATIVE FROM MROW(),MCOL()
ENDIF

*-- Add a separating line
IF CntBar("ShortCut")> 0
DEFINE BAR 1010 OF Shortcut PROMPT "\-" AFTER _MLAST
ENDIF

DEFINE BAR 1011 OF Shortcut PROMPT "Help" AFTER _MLAST
ON SELECTION BAR 1011 OF ShortCut Help
ACTIVATE POPUP Shortcut NOWAIT

ENDDEFINE

DEFINE CLASS EditRightClick AS AbstractHook
*-- This class adds edit features to the shortcut
*-- menu when the rightclick method fires.

PROCEDURE GotFocus
DODEFAULT()
IF POPUP("shortCut")
DEACTIVATE POPUP ShortCut
RELEASE POPUPS ShortCut
ENDIF

PROCEDURE RightClick
DODEFAULT()
IF ! POPUP("ShortCut")
DEFINE POPUP shortcut SHORTCUT RELATIVE FROM MROW(),MCOL()
ENDIF
IF CntBar("ShortCut")> 0
DEFINE BAR _med_sp300 OF shortcut PROMPT "\-"
ENDIF
DEFINE BAR _med_cut OF shortcut PROMPT "Cu\<t" ;
KEY CTRL+X, "Ctrl+X" ;
MESSAGE "Removes the selection and places it onto the Clipboard"
DEFINE BAR _med_copy OF shortcut PROMPT "\<Copy" ;
KEY CTRL+C, "Ctrl+C" ;
MESSAGE "Copies the selection onto the Clipboard"
DEFINE BAR _med_paste OF shortcut PROMPT "\<Paste" ;
KEY CTRL+V, "Ctrl+V" ;
MESSAGE "Pastes the contents of the Clipboard"
DEFINE BAR _med_slcta OF shortcut PROMPT "Se\<lect All" ;
KEY CTRL+A, "Ctrl+A" ;
MESSAGE "Selects all text or items in the current window"
DEFINE BAR _med_clear OF shortcut PROMPT "Cle\<ar" ;
MESSAGE "Removes the selection and does not place it onto the Clipboard" ACTIVATE POPUP Shortcut NOWAIT

ENDDEFINE

DEFINE CLASS AbstractTextBox AS TextBox
*-- Set the oHook reference
PROCEDURE setohook( txPassed)
LOCAL llRetVal
DO CASE
CASE ISNULL( txPassed)
THIS.oHook= .NULL.
llRetVal= .T.

CASE TYPE( "txPassed")= "O"
IF TYPE( "THIS.oHook")= "O" AND ;
PEMSTATUS(THIS.oHook, "SetoHook", 5)

THIS.oHook.SetoHook( txPassed)
ELSE
THIS.oHook= txPassed
ENDIF
llRetVal= .T.
ENDCASE
RETURN llRetVal
ENDPROC

PROCEDURE release
*-- Release related hook objects
IF TYPE("THIS.oHook") <> "U"
THIS.oHook= .NULL.
ENDIF

PROCEDURE GotFocus
*-- We use _BOX as a flag
_BOX= .T.
*-- Delegate to the implementation chain
IF ! ISNULL( THIS.oHook) AND ;
TYPE( "THIS.oHook") = "O" AND ;
PEMSTATUS( THIS.oHook, "GotFocus", 5)
RETURN THIS.oHook.GotFocus()
ENDIF

PROCEDURE RightClick
*-- We use _BOX as a flag
_BOX= .T.

*-- Delegate to the implementation chain
IF ! ISNULL( THIS.oHook) AND ;
TYPE( "THIS.oHook") = "O" AND ;
PEMSTATUS( THIS.oHook, "RightClick", 5)

RETURN THIS.oHook.Rightclick()
ENDIF
ENDPROC

ENDDEFINE

DEFINE CLASS MyTextBox AS AbstractTextBox
*-- Reference to a hook object
ohook = .NULL.
Width=150
ToolTipText = "Right Click Me"
StatusBarText= "Right Click Me"
Value = "Right Click Me"

ENDDEFINE

Conclusion

Template methods call hook methods, and hook methods are adaptable by standard subclassing mechanisms. Hook operations are places where optional adaptation is meant to happen. Templates and hooks are related structures that can be combined in a variety of ways. One of these combinations, the case where template classes inherit from hook classes permits a surprising degree of configurability and maintainability.

Why?

Because if a template class inherits from a hook class, then the template class is a hook. Moreover, since template classes are (by definition) themselves hooked, then there is really no limit to the behavior that can be attached and chained to a particular template method in a template class.

Relax, this took a long time to sink into me too.

Author’s note: Portions of this document have appeared elsewhere, notably in FoxTalk Magazine, and in the abstracts of regional Visual FoxPro conferences in Canada, the United States, and Europe.

Summary of Selected Reading and Resources

Books and Articles

Alexander,C., et al. A Pattern Language. New York: Oxford University Press, 1977. ISBN 0-19-501919-9

Alexander,C., et al. A Timeless Way of Building. New York: Oxford University Press, 1978.

Black, S. (1995) Pattern Implementation in VFP, European Visual FoxPro Developers Conference '95 session notes, E-PATT, Frankfurt, Germany. And also: GLGDW '95 session notes, #30, Milwaukee, WI.

Brooks, F, (1975 and 1995) The Mythical Man Month.. Reading, MA. Addison Wesley. ISBN 0-201-83595-9.

Buschman, F, and Meunier, R (1995) A System of Patterns. Chapter 17 (p.325) in a compilation work by Coplien, J, and Schmidt, D (1995) Pattern Languages of Program Design. Reading, MA. Addison Wesley.

ISBN 0-201-60734-4.

Buschman, F, Meunier, R, Rohnert, H, Sommerlad, P, and Stal, M (1996) A System of Patterns. West Sussex, England. John Wiley & Sons. ISBN 0-471-95869-7.

Coad P, North, D, and Mayfield, M, (1995) Object Models: Strategies, Patterns, and Applications. Prentice Hall. ISBN 0-13-108614-6. Also a helpfile: STPTHLP.ZIP in CIS.CaseForum, Lib 3

Coplien, J. Advanced C++ Programming Styles and Idioms. Reading, MA: Addison Wesley, 1992.

Coplien, J, and Schmidt, D (1995) Pattern Languages of Program Design. Reading, MA. Addison Wesley. ISBN 0-201-60734-4.

Gamma, E., Helm, Observations on Observer, Dr. Dobb’s Sourcebook, September/October 1995.

Gamma, E., Helm, R., Johnson, R, and Vlissides, J. (1994) Design Patterns, Elements of Object Oriented Software. Reading, MA. Addison Wesley. ISBN 0-201-63361-2

Hay, D (1995) Data Model Patterns: Conventions of Thought. Dorset House.

Helm,R, and Gamma, E. The Courrier Pattern. Dr .Dobb's Sourcebook Jan/Feb 1996. Miller Friedman Inc, San Francisco.

Juancarlo Anez. (1995) A Perfect Fit. Windows Tech Journal, September 1995, Oakley Publishing Company, Springfield OR.

Pree, W (1995) Design Patterns for Object Oriented Development. Reading, MA. Addison Wesley and ACM press. ISBN 0-201-42294-8.

Rohnert, Hans, PLOP 96 Conference Proceedings, Addison Wesley (1996)

Vlissides, John, Seven Habits of Successful Pattern Writers, C++ Report, Vol 7 no 9, November-December 1995, SIGS publications, New York NY.

Some interesting internet sites:

http://www/state.sd.us/people/colin/fox_page.htm

The Cunningham and Cunningham inc homepage, http://c2.com has a description of pattern history, a description of the Portland pattern form, guidelines for writing patterns in Alexander's style, and several patterns and pattern languages and links to other sites.

The patterns homepage: http://st-www.cs.uiuc.edu/users/patterns/patterns.html Maintained by Richard Helm.

Conferences:

PLOP ’96, "Pattern Languages of Programs", Sept 4-6 1996 in Allerton Park Il. http://www.cpl.uiuc.edu/~plop/