Quite a few years ago I landed a Delphi assignment to, among other things, develop a media injector application for a Swedish television broadcaster. It would be part of a much larger system, and its responsibility was to move different clips of mp4 files from one place to another according to a time schedule that arrived as XML.
That app was my first contact with factories, and that implementation wasn’t even a real factory. But it did change how I do a lot of things.
What is a factory?
Firstly, what is a factory (in a coding context)? Well, I’m sure there are nice descriptions and ‘rules’ defining a factory, but in my world, it is simply a selector of things.
Consider this. Often my applications use a bunch of frames, some of which are even nested. Earlier, before my factory era, I would set the frames up, add them to a form programmatically using if statements to decide what frame I wanted to show at a particular time.
These sets of if statements could get quite long.
if MainForm.CurrentFrame = 'login' then TLoginFrame.Create( Application.MainForm ).Parent = CurrentFramePanel if MainForm.CurrentFrame = 'admin' then TAdminFrame.Create( Application.MainForm ).Parent = CurrentFramePanel if MainForm.CurrentFrame = 'list' then TListOfThingsFrame.Create( Application.MainForm ).Parent = CurrentFramePanel if MainForm.CurrentFrame = 'detail' then TDetailsFrame.Create( Application.MainForm ).Parent = CurrentFramePanel
Using a factory would simplify such code.
CurrentFrame := TFactory.GetCurrentFrame( TheFrameName );
All I have to do to get this to work is to have the TFactory class (it may be static or an instantiated object, a simple function or as I tend to do lately, a class inheriting from the generic TDictionary<TSomething> class.
The above example implies the returning of an instantiated object, but a factory may well return an enumeration, a value, a class type, an interface or whatever you may have need of at this particular time. For instance, just now, my team is tasked to renovate a mechanism spawning Windows processes depending on the actions of the user. About 40 or 50 menu items (doubled in popup menus and buttons) should start a specific application, and naturally, my suggestion of a solution pattern is using a factory.
So why should you use factories?
One of the most important reasons for using factories, in my humble opinion, is to separate concerns and remove dependencies on your code. In my first example above, you…
- push the logic for determining what frame to show from the main form into the logic of the factory
- eliminate the need of including the frame unit in your uses clause, thereby removing a dependency. Instead, you inject the code when it is needed.
So why would you want to push that logic elsewhere? After all, the state engine is the main form, is it not? Shouldn’t the main form be the controller of what it shows?
A common problem with Delphi applications is that the main form grows to hold every single piece of logic in the application. Everything ends up in the main form, and suddenly it is too large to handle. the worst example I’ve seen is an application where the main form had over 55.000 rows of code, and just about every bit of business logic held in components, lists and panels of the actual main form.
Pushing these decisions to more specialized locations help to keep the main form clean. (On a side note, in my opinion, no logic at all should be kept in the main form unit).
Interfaces in factories
Returning an interface to an object is often a good choice for a factory for several reasons, the most important being
- eliminating even more dependencies (as the declaration of the object’s interface should (could) be centralized in a single (or a few) interface units).
- taking advantage of the reference counting in Delphi interfaces, eliminating the need for destroying the objects that the factory returns.
A small example
I’ve created a small example of a factory returning one of three frames to the main form depending on which button the user clicks.