Jefferey A. Donnici
This months Best Practices column closes out the "Seeing Patterns" series with an examination of the Factory Method pattern. The Factory Method design pattern is the second Creational pattern to be discussed in this series. While its not a terribly complex pattern, it does have a few unique traits that make it distinctive among the patterns Jefferey Donnici has discussed so far. When a class is responsible for creating other objects at runtime, the Factory Method pattern allows the subclasses to decide which objects to instantiate.
One of the many problems that object-oriented software development is meant to solve is the difficulty with creating dynamic applications that change their behavior at runtime. Any number of factors might affect a systems behavior, from user interaction to historical data values, and in many cases theres more than one factor to be considered at a time. As such, our applications have to have a variety of behaviors and functionality to address these conditions. Because we encapsulate behavior and functionality into distinct objects, this typically means dynamically creating an object based on the runtime needs of the system.
This months pattern, and the final pattern in this "Seeing Patterns" series, is the Factory Method. This pattern helps address this problem of "dynamic creation" by providing a design solution that allows the application to create different objects based on the current system state. As with the last couple of patterns, the Factory Method is a pattern that doesnt get as much "word of mouth" in online discussions and printed publications as some of the other, more popular patterns (the Bridge and Mediator patterns come to mind). My guess is that the Factory Method pattern, like the Template Method I discussed a couple of months ago, is just one of those patterns that doesnt immediately strike an "A-ha!" response from developers who read about it. Youll learn in this article that theres really no rocket science happening in designs based on this pattern; its a fairly straightforward pattern that, when you need it, can really be a lifesaver.
And for the final time in this series, let me run through the essential introductory information about the "Seeing Patterns" series. The idea behind this series, which started with the November 1998 issue of FoxTalk ("Seeing Patterns: The Bridge"), is to look at object-oriented design patterns individually, with a different pattern being discussed each month. The thing that makes these discussions different from most patterns articles in the object-oriented world is that the patterns are presented using Visual FoxPro examples and concepts. All of the examples use Visual FoxPro, and the VFP base classes are referred to when a specific type of class is being discussed. If this is the first month that youre tuning in for this series, Id humbly suggest that you check out some of the earlier Best Practices columns in this series. The first few columns in the series contain basic information about the concepts behind object-oriented design patterns, as well as details about the different types, or families, of patterns. The August and September 1999 columns served as a "mid-semester" break, using a question-and-answer format to discuss some of the common questions that have come up in the series. If this is the first month youre joining the series, those issues might be helpful in terms of catching up with whats been covered thus far.
Every pattern in this series, including this months Factory Method pattern, was initially presented to the object-oriented development community in Design Patterns: Elements of Reusable Object-Oriented Software, by E. Gamma, R. Helm, R. Johnson, and J. Vlissidescommonly referred to as the "Gang of Four" or "GOF" (published by Addison-Wesley, ISBN 0-201-63361-2). This book is also available on CD-ROM, including source code examples and hyperlinks between chapters and topics. As you read any of the columns in this series, you might find it useful to have the book or CD-ROM nearby as a reference.
And finally, its important for me to point out that Visual FoxPro is merely the language Im using to demonstrate the patterns in these series. The patterns, however, are object-oriented design patterns and not Visual FoxPro design patterns. Every pattern in this series can be (and is) used in just about any other object-oriented development environment. And because an "object-oriented design pattern" describes a solution to an object-oriented design problem, any implementation examples (code or diagrams) used in this series shouldnt be assumed to be the only possible implementations of designs based on these patterns. In other words, your mileage may vary, some restrictions apply, contest rules are subject to change, and this offer not valid in Wisconsin.
The programmatic interface consists of the member methods (and those methods parameters and return values) that an object uses to interact with other objects. If youve made member properties publicly available in your class definitions, then those properties also become a part of the objects interface at runtime.
As with the Template Method pattern (see the Best Practices column in the November 1999 issue of FoxTalk"Seeing Patterns: The Template Method"), the Factory Method pattern centers around a single method on an objects interface and, more importantly, the "door" that that method opens to increased reusability and/or functionality. Where the Template Method is a behavioral pattern, therefore addressing runtime object behavior issues, the Factory Method is a creational pattern.
Creational patterns address some aspect of the instantiation process wherein a class definition becomes an object within the system. Creational patterns serve to abstract the instantiation process so that it can be used to dynamically affect the behavior of the system based on the systems runtime state. As explained in Design Patterns, there are two types of creational patterns: "A class creational pattern uses inheritance to vary the class thats instantiated, whereas an object creational pattern will delegate instantiation to another object." Prior to this month, the only other creational pattern to be discussed in this series was the Singleton pattern (see the May 1999 issue of FoxTalk). While the Singleton is an object creational pattern, one of the fundamental assumptions in the Factory Method is that inheritance will be used, making it a class creational pattern.
With the Factory Method pattern, the idea is that a single method handles the creation of certain types of objects, providing an instantiated object to the system when its finished. Because this method is serving to create the object, the purpose of the word "factory" in the patterns name becomes immediately obvious. Most of the time, the Factory Method pattern is used with application frameworks or highly reusable and modular components. The component will typically have a method (or more than one) that creates some other object needed by the component, but the component doesnt know in advance what type of object it will be interacting with. Instead, it calls the factory method with the understanding that an object of a certain class-type will be created and either returned or otherwise made available to the component. By expecting an object of a specific class-type, the component is expecting an object thats at least a certain class within a class hierarchy; in other words, either a specific class or some subclass of that class.
By providing the Factory Method pattern, the component is stating that its subclasses should know which class to instantiate. As mentioned previously, this reliance on inheritance is what makes this pattern one of the "class creational" patterns (see Figure 1).
You might have an abstract "creator" class that just provides the basic implementation around the factory method and leaves the decision over which ancillary class to instantiate (as well as how to instantiate it) entirely to the subclass.
You could use a concrete "creator" class that provides a basic, "default" implementation so that the majority of situations are covered, and the creator class subclasses can handle the exceptions.
Another option is to use some external mechanism for determining the class to instantiate, such as a GetUtilityClass or similar method.
Finally, you might use a parameterized Factory Method so that a single "creator" can create multiple utility classesthe indicator for which class to instantiate comes into the Factory Method as a parameter, perhaps with the resulting object itself returned as the return value.
Regardless of which method you choose for deciding which class to instantiate, youve gained a significant amount of flexibility and reusability by having the Factory Method within the class create the object the component will need at runtime. In doing so, the Factory Method serves as a "hook" for subclasses to over-ride to provide some other, more specialized, version of the classs functionality (at least with regards to its associative relationship with other objects at runtime).
At the core of the Codebook framework is the cApplication class, which is the abstract class from which any Codebook application object is subclassed. Because the cApplication class is a subclass of the cChildCollection class, it has a LoadChildren method that adds a variety of member objects to the application object (the baseclass for the collection classes is Container). For more details on how this works, see the Template Method discussion in the November 1999 Best Practices column. One of the objects thats added as a member, or child, object is the oToolbars object, a collection of the applications toolbars. This is specified by the LoadChildren method in the population of the aChildren member array:
laChildren[2, CHILD_CLASS] = "CToolbarCollection"
laChildren[2, CHILD_NAME] = "oToolbars"
An instance of the cToolbarCollection is created, given the name oToolbars, and added as a member object to the application. With that in place, the application has a place to "hang" the toolbars that it might need during the lifetime of the application.
But how does it know which toolbar to create initially? Enter the Factory Method pattern.
While the process for creating a toolbar can remain consistent from one application to the next, especially given the strong toolbar base classes provided, the decision over which toolbar to create is left to the subclassesthat is, those classes that represent actual applications.
Within the cApplication class, theres a Do methodthis method provides the fundamental wait state for any Codebook-based application. This is where the READ EVENTS for the application occurs, and theres not much for that method to do but "run" the core application. Prior to the Do method being called, the development environment settings have been saved, and different settings have been changed as required for the application. This leaves the basics for the Do method:
THIS.ShowMenu()
THIS.ReleaseSplash()
THIS.ShowToolbar()
*-- Shutdown handler omitted for clarity
READ EVENTS
In total, there are fewer than 10 lines of code in the Do method, but our focus for this discussion is on the ShowToolbar method. Its there that we can see the Factory Method implemented in a clear, concise fashion. This method simply adds the toolbar object to the oToolbars collection previously created. Again, the means of adding the toolbar is consistent for all subclasses of cApplication, but each application must know which toolbar to create as part of its initial startup.
Here are the relevant lines of code from the ShowToolbar method:
IF NOT EMPTY(THIS.cMainToolbarClass)
*-- UI message call omitted for clarity
IF THIS.oToolbars.Add(THIS.cMainToolbarClass)
THIS.oMainToolbar = ;
THIS.oToolbars.Get(THIS.cMainToolbarClass)
THIS.oMainToolbar.Show()
ENDIF
ENDIF
Notice the very first line of codethe method is checking to see whether a property of the application class, cMainToolbarClass, is present. Its there that our factory method, ShowToolbar, determines in the subclasses which toolbar class to instantiate. Assuming that the cMainToolbarClass property is populated with a string containing the name of a toolbar class definition available to the application, that toolbar becomes the main toolbar for the system.
From there, the method proceeds to tell the oToolbars collection to add an instance of that class to itself. If that process succeeds, the method gets an object reference to that new toolbar and assigns it to its own oMainToolbar object propertythis allows the application and its main toolbar, presumably the toolbar referenced most often by the application, to communicate directly via that object reference. Finally, the method calls the Show method to make the toolbar visible to the user.
Ta-da! The Factory Method pattern really is that simple. While there are probably dozens of variations on this particular implementation, the motivating principle behind this pattern is present. The basic idea is to provide a method in a superclass that will create some sort of utility object that the overall component will need at runtimethe key, however, is that the class defers to its subclasses to decide which class to instantiate and how that class should be instantiated.
Next month, the Best Practices column returns to "normal" (Yeah, right!Ed.), with the usual fare of topics chosen to separate the hackers from the programmers from the professional software developers. As always, feel free to let me know if you have any suggestions or comments for this column.
Jefferey A. Donnici is the senior Internet developer at Resource Data International, Inc. in Boulder. Jeff is a Microsoft Certified Professional and a five-time Microsoft Developer Most Valuable Professional. 303-444-7788, fax 303-928-6605, jdonnici@compuserve.com, jdonnici@resdata.com.