Design Patterns deal with the fundamental techniques of how and why you write code in a certain way. This is in contrast to the more typical article that is about the VB.NET syntax that you need to use to make the code work correctly. In general, a design pattern will work in a whole list of different languages because it's all about the process and not the language. This article is one of a series that explains the popular design patterns using the syntax of Visual Basic - VB.NET. The subject of this article is the Factory design pattern.
Just to be clear, "Design Patterns" are actual code prototypes. A book like Fred Brooks' classic The Design of Design is about the overall management of the process.
Some other articles in this series include:
-> The Delegation design pattern
-> The Singleton design pattern
The Factory Design Pattern
Design patterns aren't standards, but they're widely accepted "best practice" templates for code that have been carefully worked out for decades. But because they're not standardized, there are differences in names and different implementations. The factory pattern is usually classified as part of a family of patterns called "creational patterns" ... they're ways that your code can "create" objects. A common definition of the factory pattern goes like this:
A pattern to define an interface for creating an object where the classes that implement the interface decide which class to instantiate.
If this is less than completely clear to you, just think about the name "factory" instead. The name itself suggests the explanation. When you want to create a whole bunch of objects that are essentially the same but have specific differences in the details, you build a factory. A car factory builds the same model car where the individual cars have only slightly different features. The decision about the features("which class to instantiate") is made when the factory starts building the car ("implements the interface").
In this case, the client is probably a car dealer and the product is the car. But in the general case, they could be a lot of things:
-> A restaurant and menu items (big chains do it exactly this way)
-> A travel agent and trip itineraries
-> A security system and new accounts
One key to understanding this pattern is to clearly understand that there is a level of "abstraction" that makes the "client" and the eventual creation of a "product". In computer science, this is sometimes called "decoupling". Coding the parts of a system so the individual software blocks that don't depend on each other. The advantages include:
-> Avoiding the duplication of identical code.
-> Keeping information or resources out of classes that it shouldn't be in.
-> Allowing the generated objects to be centralized for consistent behavior.
The way this is done in the factory pattern is to code two modules that are jointly responsible for creating objects. If the detailed specifications for a car are kept in a file identified by DetailSpecID, it might look like this in our example:
MustInherit Class Car
Public MustOverride Property DetailSpecID As Integer
Public MustOverride Property ModelName As String
End Class
MustInherit Class CarFactory
Public MustOverride Function MakeCar() As Car
End Class
(MustInherit is covered in this article.)
A UML diagram of this pattern looks like this:
--------
Click Here to display the illustration
--------
Doesn't help that much? I'm feeling that way about UML these days too. How about this instead.
--------
Click Here to display the illustration
--------
You can see that the Product (a car in this case) is decoupled from the Client (a car dealer who wants to order a car to be built). Another class actually does the work. Here's the code for that:
Class ConcreteCar
Inherits Car
Public Overrides Property DetailSpecID As Integer = 12345
Public Overrides Property ModelName As String = "This Year's Model"
End Class
Class ConcreteCarFactory
Inherits CarFactory
Public Overrides Function MakeCar() As Car
Return New ConcreteCar()
End Function
End Class
I've used the names ConcreteCar and ConcreteCarFactory, not because we're going to make them out of cement, but because these classes are the ones that actually do the work and these names are traditional in the literature of design patterns. In a more real-world system, a DetailSpecID might refer to thousands of lines of specific instructions for SCARA robots, but in this case I'm just returning a number for simplicity. Similarly, the MakeCar function might start a whole system, but here I'm just returning a new instance of ConcreteCar so I can access the properties.
To run this system (start the factory running), just code another class like this ...
Class CarAssembler
Public Sub AssembleCar(ByVal factory As CarFactory)
Dim car As Car = factory.MakeCar()
Console.WriteLine("Assembled a {0} with Specifications at ID: {1}", _
car.ModelName, car.DetailSpecID)
End Sub
End Class
... and call it.
Dim factory As CarFactory =
New ConcreteCarFactory()
Call (New CarAssembler()).AssembleCar(factory)
To illustrate why we do this, let's assume that Maxamillion Bigbucks just purchased the car company and has decided to add offshored car production. Your job, as programmer-in-chief, is to modify the system so that cars can be ordered from offshored plants as well. Without the factory model, you might have to change quite a bit of code, but since you were far-sighted enough to use it, all you have to do is add the new classes (remembering again that the properties and the function are just place holders to give you the idea and a real system might be very complex) ...
Class OffshoredCar
Inherits Car
Public Overrides Property DetailSpecID As Integer = 54321
Public Overrides Property ModelName As String = "Offshored Model"
End Class
Class OffShoredCarFactory
Inherits CarFactory
Public Overrides Function MakeCar() As Car
Return New OffshoredCar()
End Function
End Class
... and call the new classes instead. You can mix and match which factory you use to meet the needs of Mr. Bigbucks and his customers.
Dim factory As CarFactory = Nothing
factory = New OffShoredCarFactory()
Call (New CarAssembler()).AssembleCar(factory)
factory = New ConcreteCarFactory()
Call (New CarAssembler()).AssembleCar(factory)
Notice that the old factory CarFactory, and the CarAssembler didn't change at all.
