Time to continue from yesterday's Factory Method Pattern by exploring the Abstract Factory Pattern.
Right now, we have created separate classes for both factions' units (CyborgCommando and Ghostalker). Let's change this so each faction has identical base classes containing logic, but slightly different configuration depending on the faction they belong to. We'll do this by implementing the Abstract Factory Pattern. I always mix this one up with the Factory Method Pattern, but it finally got through to me while writing the code for this post.
With Factory Method, we have an abstract base class containing logic and calling our abstract factory methods, which return a real implementation via subclasses. While the Abstract Factory is passed into an object where it is used as composition, and the real factory is supplied at runtime, decoupling the usage of our factory from the real implementation.
Anyway, time for the definition and then some code to make everything clear. "Provide an interface for creating families of related or dependent objects without specifying their concrete classes."
First of all, let's get rid of our faction specific units and replace them by generic ones.
You'll notice the GameUnit has been given a new constructor, an abstract class containing only abstract methods.
This class forms the definition of the Abstract Factory Pattern, it's an interface to create related objects without specifying a concrete class.
Our GameUnit class is not working with a concrete type, but with an interface, decoupling it from a real faction implementation.
We aren't much with just this interface, so let's create an implementation.
As you can see, the classes we used to illustrate the Strategy Pattern have been moved to this factory implementation, which means our GameUnit and all other unit implementations are now working with interfaces rather than concrete implementations.
Another thing left to do, is to let the units get their information from the abstract factory.
All that is left, is a small change to our two InfantryFactories to pass in the correct FactionDetailsFactory to each unit, and our test case is ready to run again, without having to change it.
You might wonder what the IBuilding interface is suddenly doing there, well, I cleaned the code a bit up and decided to place everything in separate files as it should. Never done it before to keep it simple for these articles, but I didn't like the code adding up.
With the Abstract Factory Pattern implemented, our results looks like this:
So, here's the uploaded solution again, changed quite a bit since last time, take your time to have a look at it.
Some additional information on the Abstract Factory pattern: