The abstract factory creational pattern allows you to organize different sets of classes that work together so they get created together. This lets you change from one group of classes to another by configuring a different abstract factory.
You first need to create an interface that’ll be common for each type of factory. This interface will have create methods for each object that you want created by a factory. These individual create methods are factory methods and are implemented by the concrete factory instance. What makes this pattern different from just the factory pattern is this interface that brings together many different types that all need to work together. By switching to a new factory, other code can start creating different instance types that are designed to work well together as this new factory determines.
Each create method will need to return an interface or base class because the actual type that’s returned will depend on what concrete type the factory decides to create. Since there are many different factories each trying to return different types for the same create method, we need a common interface for each of these.
The episode also describes some problems you might encounter with this pattern and some suggestions for modifying the basic pattern to fit your needs. Listen to the full episode or read the full transcript below.
The basic description says that this pattern provides an interface that’s used to create families of classes without specifying the exact classes.
I put this pattern after the other creational patterns because it sometimes uses the other patterns. It’s called an abstract factory not because the concept is abstract but because the factory itself uses an abstract base class or an interface.
The simple and most direct way that this pattern works is from an interface. And I’ll normally just refer to this as an interface because that’s shorter than constantly saying abstract base class or an interface. But they’re the same thing really. You define an interface with methods that create and return instances of other classes.
Each of these methods works like the factory pattern. In fact, you can sort of think of this pattern as a factory that’s been extended to work with many classes. Each method returns a concrete class but as a base class.
Let me give you an example to make this clear. We’ll use the adventure game. We need to create lots of object in the game including buildings, trees, and even clouds in the sky. You start out by creating an interface to define basic characteristics of all buildings. And the same thing with trees, clouds, and anything else that you want to participate in this pattern. This will include anything that needs to work together.
But wait, what do I mean by working together? How can a tree work together with a cloud? They don’t need to have any direct interaction. But since trees are outside, it’s reasonable to assume that there will be clouds outside as well. If you’re creating trees, then you’ll likely want to create some clouds to go along with the whole scene. That’s what I mean by them working together.
Why is this important? Why do we need to put all these things behind an abstract factory? Let’s say that all these things work well until you have to implement the ability for the hero to walk around in a dream. Now, you’re going to want dream houses, dream trees, and even dream clouds. Maybe they all look a bit different. Maybe the hero can just walk right through the walls of a dream house.
You don’t want to mix these. It would be very bad to sometimes spot a purple dream cloud in an otherwise normal sky. Since we don’t want to mix these concepts, your game can switch modes. It’s either in regular mode or in dream mode. Or maybe even some other mode. You can get into a particular mode and stay there by switching factories.
You see, the factories also have an interface with methods like createHouse, createTree, and createCloud and each of these methods returns the base class for each of these items. The other code that wants a house will call createHouse and will get back a house. It doesn’t know exactly what kind of house. Just that it’s a house. The actual factory doing the creating is a concrete class that implements all the create methods in the abstract factory interface.
When the code want to enter a normal mode, it creates an instance of the abstract factory. Let’s call this the normalFactory. The code then uses this normal Factory anytime a house, tree or cloud needs to be created. The normalFactory only know how to create normal houses, trees, and clouds.
Then when the game needs to go into dream mode, the code will stop using the normalFactory and start using the dreamFactory. With that little change, everything else remains the same. The rest of the code doesn’t know or care if the actual house is normal or a bit wavering.
One of the problems with this pattern is the need to have a factory method for each object that can be created. I’ll explain some ways that you can work around this right after this message from our sponsor.
( Message from Sponsor )
There’s actually a few changes you might be interested in making to this pattern depending on your needs. I already mentioned the need to have a method for each object that can be created. Why is this a problem?
If you only have a few class types that you want to create, then maybe this is not a problem. But if you have too many. And I’ll leave how many is too many for you to decide. It might be that 10 is too many for your application. Or maybe you’re okay with up to a hundred. At some point though, your abstract factory interface is going to get filled up with methods that all create something. This problem will be worse if new class types keep getting added to the interface on a regular basis.
Each time a new class type needs to be added to the abstract factory, not only the interface needs to change, but each concrete factory implementation of that interface needs to be updated to add the new method.
One possible solution will be to change the create methods to allow them to be more applicable. So instead of having createRedHouse and createGreenHouse methods, you may want just a createHouse that takes a color as a parameter. Now this is probably not the best example because color should really be a property of just a house class and not used to distinguish house types. You could still give a color parameter to the createHouse method if you want. But a better example has to do more with different types. Let’s say you start out with separate createHouse, createBarn, and createWall methods. Houses and barns are similar but different enough that you might consider separate classes. But walls are definitely going to be a different class. They’re all buildings though and maybe what you can do is to combine them into a createBuilding method that takes a parameter to specify what kind of building.
This parameter could be a string or maybe an enumeration. Strings have an advantage that they’re up to the create method to interpret however it wants. But strings are also easy to misuse. Do you want other code to be able to pass the string “house” in all lower letters and another code to pass “House” with a capital H? What if some code misspells house completely and passed “haus”? In some regions, houses are spelled haus. An enumeration is safer but then still needs a code change when you want to allow a new building type to add a new enumeration value.
The other tradeoff that the parameterized create method causes is now, all buildings have to be returned as a common interface. Sure, the calling code that asked to create a wall will know it’s a wall, but it’ll need to work with that wall as if it was just any other building. This may or may not be acceptable.
If you take this approach to its ultimate end, then you have just a single createGameObject method that can create anything based on what you ask for. The downside is that everything now becomes a gameObject.
You might be able to use a different pattern to tell one gameObject from another but that’s getting outside of the topic of how they’re created in the first place. That’ll be a future episode.
Beyond just the number of methods in the abstract factory interface, another problem is that this pattern relies on separate concrete factory types depending on what mode you want to be in. Again, if you’ve only got a few of these, then this may not be a problem. What if there are too many modes? Is there some way to reduce the number of concrete factory types?
If you just want to modify a small aspect of a factory, then you might be able to create a derived factory class from an existing factory class that reuses as much behavior of the parent factory class and then overrides one or more create methods to create a slightly different object.
But what do you do if you end up with no clear line between your modes? What if you want factories that can mix things up. At least that’s what it may seem like. If you find yourself with types that can be mixed and matched at almost random, then the abstract factory pattern is probably not what you need. There needs to be some need to switch modes for this pattern to make sense. But what if you do have several distinct modes that mix things up?
The abstract factory pattern normally requires a specific concrete class of factory for each mode. But you might be able to use the prototype pattern to configure a factory. This would allow you to reduce the number of classes for factories to as few as just one. This one factory would need some way to configure it or load the types that it’ll later be creating before it can be used.
Think of it like you’re preloading the combination of types for each create method with a sample of what each create method will create. That’s the prototype pattern that was explained in episode #61.
When yo want to use this pattern, just start with the general idea and customize it to fit your needs. This may mean that you make use of several patterns. That’s okay and a little experience will help you to make those decisions. Until you get that experience, the basic implementation of this pattern will probably still be better than not using any pattern at all.