Tutorial Design Patterns - Creational patterns
Factory Method pattern
Overview
|
| Degree of Difficulty | 2 |
| Structural Complexity | 4 |
| Extra-Pattern Complexity | 9 |
| Implementation Specificity | 2 |
Intent according to the GoF
"Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory method lets a class defer instantiation to subclasses" [GoF 94]
Intent seen through Real Life
I like to call Factory method the Substrate/Helper Method. It allows us to create an interface for a main class which dictates that a helper class is instantiated to assist the main class in its operations.
Real life examples abound.
As a quick reference to the preceding discussion on the Builder pattern, let's say we had to bake several types of pastries. We might find it more convenient to use a different type of baking tin for the different types of baked products. So for example, cupcakes/muffins are best baked in a cupcake tray, birthday cakes in a square tin and wedding cakes in a round tin.
As another example, we can see where flus have particular mediums that they prefer to live off. The flu which we come down with from time to time (flu season or not) prefers humans, whereas bird flu (for now), prefers birds. The whole world led by the WHO is hoping that it will stay that way.
Additionally, different types of paper are better suited to different printers. Inkjet printers love glossy paper, Laserjets love plain paper and Dot matrix love tractor feed paper.
In all the examples, there is a main object and a helper object which is of particular interest. In all cases, the main object works best with a particular helper/substrate object and so should be able to choose which helper class to work with. It should not have the choice of helper class imposed on it by the client. In all cases, however, the helper class conforms to an interface. So the following table applies. Notice we say "works best with" since sometimes the main class can work with a different helper-class.
|
| Main Class | MainClass methods | Helper Class | Helper Class methods |
| BirthdayCake | Bake | SquareTin | ContainHotCakeMix |
| WeddingCake | Bake | RoundTin | ContainHotCakeMix |
| Muffins | Bake | MuffinTray | ContainHotCakeMix |
| BirdFlu | Infect | Bird | HostParasite |
| HumanFlu | Infect | Humans | HostParasite |
| DotMatrix | Print | TractorFeedPaper | BindInk |
| LaserPrinter | Print | PlainPaper | BindInk |
| InkJet | Print | GlossyPaper | BindInk |
Also note that for the methods in the main class which affect the helper/substrate class, it is likely that the helper/substrate class will have a corresponding method which is complementary to the method in the main class. This is so because the helper class chips in and does some of the work for the main class when the corresponding main class's method is called. You could say that the main-class method and the helper-class method have a reciprocal relationship.
The idea behind the Factory Method, is to ensure that any of the several classes you work with, are able to instantiate the helper class which it is best suited to work with. In our printer example, imagine that a printer has a built in connection to the internet which sends an email to a paper-supplier. This paper-supplier manufactures the type of paper which it works best with. This email would of course be sent when the paper supply is running low, in order to have more paper delivered.
In this sense the printer is responsible for choosing the type of paper to work with and this is in fact hard wired into the printer. This is how the factory method operates. It simply ensures that the class which works best with the main class is instantiated and conforms to an interface which allows it to perform some work which is useful to the main/instantiating class.
In the printer example, we can think of the Abstract-Creator as being printers in general. The abstract-creator class ensures that main-classes which implement its interface, implements a method to do the main work we are interested in. In this case it is the work of printing. The interface also ensures that printers implement a method which instantiates a helper class which performs a subset of the functionality. Imagine a printer running out of paper. Certainly it can continue to spray ink but it will just be messing up itself with ink. Instead, a smart printer performs an action which "instantiates" the feeding of paper into its tray. It usually does this by flashing a light to indicate that you should load paper. In this case therefore, the abstract-class is like an IEEE or UL or FCC specification which dictates that before a printer can operate, it must ensure that paper is loaded into its tray for it to print on, and that it is the most appropriate type of paper.
A specific type of printer such as an HP840 would specify that it wants glossy paper. By implementing the "Print" methods and the "Get Appropriate Paper-Type" method, it resembles the concrete-creator class in the pattern. A Printer such as the HP Laserjet 5 would implement the same method by acquiring plain paper.
Abstract-Product in the pattern specifies the helper-class which must be created to help the main class do its work. So in the printer example, our Abstract-Product would indicate that it is a "paper" class which implements an "Accept Impression" method. But it allows the paper to implement its own approach to binding the ink to accept the impression.
Concrete-Products in the pattern are represented by the Specific type of papers available and in our case, specifically by Glossy paper, which not only implements the Impressionable interface, but specializes in the way it holds the ink and the type of ink it can hold.
Intent seen through O/S & Applications
Within Windows XP, there are a set of file associations within the folder options which indicate the program which will open the particular file. The program in this sense is the main class and the file type is the substrate class (the program works on the contents of the file-type). You could of course also look it as the file-type being the main class with the program being the helper class (the program is used in developing the contents of the file-type). It all depends on your point of view.
http://www.programmersheaven.com/articles/designpatterns/image017.gif
In a more direct way,
IEnumerable interface implements the Factory Method pattern since it enforces all classes which support it to declare a Factory Method called
GetEnumerator (which returns an enumerator class that enumerates through the items in the collection).
Scenario - Sample Code
So we have been producing albums and an important part of music production is checking the feasibility of the songs. I suppose this would normally include some market research using focus groups etc. I really don't know because I am not a producer and the little I know is from watching VH1's behind the music, so don't try my methods in your recording career :.
Important in genres such as Reggae is of course sampling. The idea being to cut samples of other people's songs for inclusion into ours.
Now sampling requires that we pay royalties, so if the sampling cost of a song is too high, then it makes it infeasible for us to sample it. So we have a feasibility checker which generally checks out the feasibility of producing the song and it looks at political correctness and whether the song has curse words etc. In our scenario code, we have a specialist method:
RoyaltyStatusChecker which determines the royalty we would need to pay. It determines this by getting the sampling fee for the song and multiplying it by a country-rate which depends on the country the song originated from.
Here now is the problem. For overseas songs, the sampling fees are in a database and for local songs the sampling fee is in a text file. Therefore the code which will get the sampling fee varies by location (overseas or local). Since we have two different classes doing the feasibility checking, we let the respective feasibility checking classes instantiate the royalty checker. The royalty checker in turn gets the sampling fee in the manner which it is best adapted to. This means that if we change the royalty database for overseas songs, it will not affect the local songs. If we convert the local songs royalty file to a database, then we can share the OverSeasChecker method, but for now they are separate and do not affect each other.
If it sounds inaccurate, then bear in mind that I just made up some rules as to how this works, so bear with me.
The Meat of the Matter
UML - General
http://www.programmersheaven.com/articles/designpatterns/image018.gif
UML - Sample Code
http://www.programmersheaven.com/articles/designpatterns/image019.gif
Participants - Sample Code
Abstract Creator[/italic] -
SongFeasibility
Ensures that classes which implement this interface must contain a factory method which returns an instance of the helper class, in this case a class which checks royalty status:
LocalRoyaltyStatusCheckers or
OverseasRoyaltyStatusChecker.
Concrete Creator -
LocalSongfeasibilty,
OverseasSongfeasibilty
Inherits from the abstract class
SongFeasibility and implements its factory method, thereby returning an instance of
LocalRoyaltyStatusCheckers or
OverseasRoyaltyStatusChecker respectively. Note that the file and database routines are transparent to the feasibility check function being carried out and the client never knows which one is used behind the scenes.
Abstract Product [/italic]-
RoyaltyStatusChecker
Ensures that classes which inherit from it provide the royalty-checking functionality which makes use of the helper class.
Concrete Products -
LocalRoyaltyStatusCheckers,
OverseasRoyaltyStatusChecker
Inherit from
RoyaltyStatusChecker and in so doing, implement routines which retrieve the royalty information. In the case of the overseas songs, the instantiated class goes to a database for royalty information. In the case of local songs, the instantiated class goes to a text file for royalty information.
Sample Code (Highlights)
Products
The Code below shows the product-classes/helper-classes. First comes the
MustInherit Class RoyaltyStatusChecker which governs the helper-classes and ensures that they provide a
GetSamplingFee method (which implements the specialized method of calculating that fee in the way it knows best).
' Abstract Product - ensures that the overridable function:
' Get Samplingfee returns a new Helper class
Public MustInherit Class RoyaltyStatusChecker
Friend Sub New() 'Constructor accesible only to the main classes which might needs its help
End Sub
'This is the helper method which complements the factory method
Public MustOverride Function GetSamplingFee(ByVal SongCode As String) As Long
End Class
Public Class OverseasRoyaltyStatusChecker ' Concrete Product
Inherits RoyaltyStatusChecker
Friend Sub New() 'Constructor accesible only to the main classes which might needs its help
End Sub
Public Overrides Function GetSamplingFee(ByVal SongCode As String) As Long
'Concrete implementation of the helper method - takes care of specialist task which
' in this case is database access
' The use of the Data classes is encapsulated in this helper method
End Function
End Class
Public Class LocalRoyaltyStatusCheckers
Inherits RoyaltyStatusChecker
' Another concrete Product - takes care of specialist task which in this case is file access
Friend Sub New() 'Constructor accesible only to the main classes which might needs its help
End Sub
Public Overrides Function GetSamplingFee(ByVal SongCode As String) As Long
'takes care of specialist task which in this case is file access
' The use of the file stream is encapsulated in this helper method
End Function
End Class
Creators - Feasibility Checker
The Code below shows the creator/main classes. First comes the
MustInherit Class SongFeasibility which governs the main-classes and ensures that they provide a
Function CheckRoyaltyStatus which calls the
GetRoyaltyStatusChecker to access the database or file and bring back the sampling fee (instead of trying to accomplish it by itself)
Public MustInherit Class SongFeasibility ' Main Class.
Protected RSChecker As RoyaltyStatusChecker ' We don't know which helper clas will be used ' ' so we declare it as the abstract-super-type
Public Function DeterminePoliticalCorrectness() As Boolean ' a main method
End Function
Public Function CheckMarketingFeasibility() As Boolean ' another main method
End Function
'Template for the Factory Method - ensures that inherited classes instantiate the helper class
Public MustOverride Function CheckRoyaltyStatus(ByVal SongCode As String) As Long
Public MustOverride Function GetRoyaltyStatusChecker() As RoyaltyStatusChecker
End Class
Public Class LocalSongfeasibilty
Inherits SongFeasibility
Sub New(ByVal songcode As String)
MyBase.New(songcode)
End Sub
Public Overrides Function CheckRoyaltyStatus(ByVal SongCode As String) As Long
'Factory Method - instantiates the helper class which will accomplish the task
' which it specializes in: the checking of Local-song sampling fees in a text file
Return GetRoyaltyStatusChecker.GetSamplingFee(SongCode)
End Function
End Class
Public Class OverseasSongfeasibilty
'similar to LocalSongFeasibility - except that it's helper method gets fees
' from a database
Client - Module
Instantiates the Feasibility Checker (main class) but is not concerned with the helper class. When it comes time for the main class to get sampling fees, it will instantiate the helper class on its own, with no help from the client.
'Declare the feasibility checker as the abstract class so that it can become any one of the
' concrete main-classes (creator -classes)
Dim SongFC As SongFeasibility
:
Console.WriteLine("Please specify L for Local song or O for Overseas song")
Dim SongType As String = (Console.ReadLine()).ToUpper
'Check which type of main class is to be instantiated
If SongType = "O" Then
SongFC = New OverseasSongfeasibilty(SongCode)
Else
SongFC = New LocalSongfeasibilty(SongCode)
End If
Console.WriteLine("The results of song construction are : {0}", SongFC.ToString)
Console.ReadLine()
Opportunities for and Costs of - Adaptation and Extension
Factory Method is not really concerned with high extensibility. It simply ensures that there is an interface governing the behaviour of a main class that dictates that it creates a helper class.
The superman boss: you've come across one or two of them in your career, the type of person who thinks they can do it all by themselves and don't bother to delegate, would do well to implement the philosophy of this pattern in their departments.
Making sure you get it right
Interface issues
There are two interfaces in this pattern. Firstly there is a governing-interface in the abstract-creator. This is implemented by concrete creators and ensures that there is a factory method within them that instantiates the appropriate helper class.
There is also an interacting product-interface which is implemented by the product/helper classes which ensures that it supplies the subset of functionality required and is interchangeable among the main classes. It means that we can swap heler classes seamlessly in the main class. So that if we moved the local song data to be in the database (instead of sitting in a file) then we can allows LocalSongFeasibilty to return and use OverseasRoyaltyStatusChecker instead of LocalRoyaltyStatyusChecker.
Namespace/Scope/Accessor issues
The scoping issues seem to be extra-pattern since the pattern doesn't seem to be affected by the ability of the client to see the product classes. No matter how you instantiate the helper class, the main class will instantiate the one it needs.
In the end the pattern seems to be concerned with a way to split up the coding-work for coding specialized classes and functions. Since the helper-classes execute specialized functionality, then chances are that security requirements are paramount. Security benefits from the application of the pattern since we can separate code into general functionality vs Need-to-know functionality. For example you could pass the Database portions to a database expert to be coded as helper classes and call them using the Factory Method. You could then lock away the helper's Database-access routines by applying a private scope to them.
Common mistakes in Pattern Literature / Pitfalls to avoid
Note the name of the pattern is "Factory Method and not "Factory". This seems to be one of the patterns which folks constituently interpret badly. The critical thing to note here is that we are zooming in on the use of a
method within the main class which makes an object that helps the main class with some of its work.
If you end up with classes in your code whose only purpose is to instantiate other classes, then those are
factory classes for sure, but you haven't implemented the
factory method. In these cases it is very likely that the prototype pattern would have fit the need more appropriately.
Good Examples in Pattern Literature
[Hol 04]
Advanced Issues
Advanced Discussion
There doesn't seem to be a lot of advanced issues. It is a fairly straight forward pattern which looks primarily at the way to divide up the work in your development team.
Explanation of Pattern subscripts
A Makes for easy modification and testing of specialised functions (hence their adaptability) without messing with general functions.
D Allows you to assign specialist tasks such as database work to experts in the area.
S+ Separates general functionality from the sensitive functions and so allows us to divide up the coding based on security-clearance.
Downloads
Back to the Design Patterns in VB.NET main page