Thursday, November 13, 2003

Abstract Factory Pattern


Description

This could be described roughly as a factory that produces factories. The usual description is a factory that produces toolkits.

Example

So what does that mean? Well, here's an example: we are consulting an entertainment company that produces movies and TV shows. Some of the classes involved would be Customer, Product, Deal, License, Market, SalesPerson. Now products can be licensed in different media such as Pay-Per-View, Premium Cable, Basic Cable, Domestic TV, International TV, etc. and the deals are very different in each media. The classes we described earlier vary across these media. For example, an international TV deal involves different languages (e.g., French, German and Italian) and many markets (e.g., France, Switzerland, Belgium, Germany, Italy), whereas a domestic TV deal involves only one language (e.g., Spanish) and one market (e.g., Los Angeles). Also the way the customers are viewed within the different media is different and the data associated with a customer is different. The sales people are paid differently and different data about them is kept in each media. So we have a set of class heirarchies something like this:


Customer
|
-----------------------------------------------
| | | |
DomesticTVCustomer IntTVCustomer PPVCustomer etc
 
 
Deal
|
--------------------------------------------
| | | |
DomesticTVDeal IntTVDeal PPVDeal etc


The code might look something like this:


Public MustInherit Class Deal
Public MustOverride Sub MakeLotsOfMoney()
'other members of deal
End Class
 
Public Class DomesticTVDeal : Inherits Deal
Public Overrides Sub MakeLotsOfMoney()
'Money making code goes here
End Sub
'etc ...
End Class
 
Public Class PPVDeal : Inherits Deal
Public Overrides Sub MakeLotsOfMoney()
'Money making code goes here
End Sub
'etc ...
End Class

And there are several other similar heirarchies for the other classes.

Now we don't want to have to write different code for every media so how can we get around it? Well, what if we create a factory that creates the objects for the different media?


Public Class MediaFactory
Public Function GetCustomer(media As MediaType) as Customer
Select Case media
Case MediaType.DOMESTIC
return New DomesticTVCustomer
Case MediaType.INTERNATIONAL
return New InternationalCustomer
Case MediaType.PPV
return New PPVCustomer
Case ETC
'etc ...
End Select
End Function
 
Public Functon GetDeal(media As Integer) as Deal
'big select statement
End Function
 
Public Function GetLicense(media As Integer) as License
'big select statement
End Function
 
'etc ...
End Class

Not bad but now we have big select statements in every method and if we add a new media we have to go into every method and add something to the select. Well, what if we make a factory that generates factories, one for each media? The resulting "factory" classes are not really factories so they often get called "toolkits". But remember that for the Factory pattern we have to create a super-class for the toolkits and then a factory class to create the toolkit objects. So let's kill two birds with one stone and put the Factory method into the super-class.

Now we have something like this:


Public MustInherit Class AbstractMediaFactory
 
Public Enum MediaType As Integer
DOMESTIC
INTERNATIONAL
PPV
'etc ...
End Enum
 
Public Shared Function GetFactory(media As MediaType) As AbstractMediaFactory
Select Case media
Case MediaType.DOMESTIC
Return New DomesticTVFactory
 
Case MediaType.INTERNATIONAL
Return New InternationalTVFactory
 
Case MediaType.PPV
Return New PPVFactory
 
Case MediaType.ETC
'etc ...
 
Case Else
Return Nothing
 
End Select
End Function
 
Public MustOverride Function GetDeal() As Deal
Public MustOverride Function GetCustomer() As Customer
Public MustOverride Function GetLicense() As License
'Other GetXXX functions go here
End Class
 
Public Class DomesticTVFactory : Inherits AbstractMediaFactory
Public Overrides Function GetDeal() As Deal
Return New DomesticTVDeal
End Function
 
Public Overrides Function GetCustomer() As Customer
Return New DomesticTVCustomer
End Function
 
Public Overrides Function GetLicense() As License
Return New DomesticTVLicense
End Function
End Class
 
Public Class PPVFactory : Inherits AbstractMediaFactory
Public Overrides Function GetDeal() As Deal
Return New PPVDeal
End Function
 
Public Overrides Function GetCustomer() As Customer
Return New PPVCustomer
End Function
 
Public Overrides Function GetLicense() As License
Return New PPVLicense
End Function
End Class

To use this pattern we first get the factory (or toolkit) we need



Dim myFactory as AbstractMediaFactory
myFactory = AbstractMediaFactory.GetFactory(media)

Then we get the specific object we want to use:


Dim theDeal as Deal
theDeal = myFactory.GetDeal()
theDeal.MakeLotsOfMoney()


Now if we want to add a new media we simply create the classes and toolkit class for the media, then add a "Case MediaType.NEWMEDIA" to the Select statement in the abstract factory class.

Resources

Data & Object Factory - Design Patterns: Abstract Factory
Wikipedia - Abstract factory pattern
DotNetExtreme - Abstract Factory Pattern

No comments: