For the last two weeks we’ve looked at two of the factory patterns: the Factory Method and Simple Factory patterns.
This week we’ll be looking at another creational factory pattern, the Abstract Factory pattern (also known as Kit).
The Abstract Factory Pattern
The Gang of Four book defines the Abstract Factory pattern as follows:
“Provide an interface for creating families of related or dependent objects without specifying their concrete classes.”
The Abstract Factory pattern is specifically intended for creating families of classes. It works with a “super-factory” that creates other factories. This super-factory can be thought of as a factory of factories.
The classic example of the abstract factory is a GUI application which is independent of the windowing system on which it is running. A GUI API has a number of “widgets” such as buttons, scroll bars, text fields and the like. Every different operating system has different looking GUI widgets.
For a GUI application to be portable using different look-and-feel standards, the widgets shouldn’t be hard-coded. We create an abstract WidgetFactory
class defining an interface for creating each kind of widget. Each widget has an abstract base class with concrete subclasses that implement that widget for specific look-and-feel standards. The WidgetFactory
‘s interface has a method that returns a new widget object for each abstract widget class. Clients call these methods to obtain widget instances, but the clients don’t know what concrete class they’re using. The client only knows about the abstract widgets. In that way, the clients stay independent of the current windowing system’s look and feel.
Adding new types of classes is hard. This requires that the factory interface is extended, which in turn requires changes to the abstract factory class and all if its subclasses.
An application usually needs only one instance of a concrete factory per family, so the concrete factories can be coded as singletons.
Abstract Factory Pattern: Example Code
Let’s say that in more advanced levels of our first person shooter game, we like to equip the players with vehicles to allow them to speed around hunting or escaping from beasts.
We want a few different types of vehicles: tanks, armoured cars, person carriers, chase cars, etc.
public enum VehicleType { BATTLE_TANK, // slow with heavy armour and weapons ARMOURED_CAR, // medium armour, medium weapons, medium speed CHASE_CAR, // no armour, light weapons, super-fast PERSON_CARRIER; // Humvee-type vehicle, light armour and weapons, fast }
For each vehicle we’d build (or allow the player to build), we would need a chassis, a body shell, different types of doors and windows, armour, weapons, etc. Although all of these vehicles need the same types of components, the components will differ depending on the type of vehicle we’re building.
This means that when we build a vehicle we can think of these components as belonging to different “families”. When we build a tank we will use one family of components; when we build an armoured car we will use a different family of components.
Let’s create a hierarchy of classes defining our vehicle components. We would have a number of these class families, one for each component: Body
,Chassis
, Windows
, Armour
, Weapons
, etc. Just the Body
hierarchy is shown below; the other hierarchies are similar.
We’ve defined a getBodyParts()
method just for illustration. The Body
interface would have more meaningful methods such as attachToChassis()
, getStrength()
, getWeight()
, etc. Obviously a better debugging/printing mechanism would be to override the toString()
method.
// Body hierarchy public interface Body { public String getBodyParts(); } public class ArmouredCarBody implements Body { @Override public String getBodyParts() { return "Body parts for an armoured car."; } } public class BattleTankBody implements Body { @Override public String getBodyParts() { return "Body parts for a battle tank."; } public class ChaseCarBody implements Body { @Override public String getBodyParts() { return "Body parts for a chase car."; } }
We will need a number of factory classes: an abstract base class and a concrete factory class for each type of vehicle we want to build. Just the AbstractVehicleFactory
base class and the concrete TankFactory
are shown here:
// Factory hierarchy public abstract class AbstractVehicleFactory { public abstract Chassis createChassis(); public abstract Body createBody(); public abstract Weapons createWeapons(); public abstract Armour createArmour(); } // Concrete factory to return the specific family of components for tanks public class TankFactory extends AbstractVehicleFactory { public Chassis createChassis() { return new TankChassis(); } public Body createBody() { return new TankBody(); } public Weapons createWeapons() { return new TankWeapons(); } public Armour createArmour() { return new TankArmour(); } }
Whenever we need parts for a specific vehicle, we instantiate the appropriate factory to create them for us. We’d still have to put all the parts together to get a vehicle, but that’s not the abstract factory’s problem: it just creates the parts. We could use a Facade pattern (we’ll cover this later) to simplify using these interfaces.
public class AbstractFactoryTest { public static void main(String args[]) { // which vehicle parts need to be made VehicleType desiredVehicle = VehicleType.BATTLE_TANK; // the factory (obviously) AbstractVehicleFactory factory = null; // Create the correct factory switch (desiredVehicle) { case BATTLE_TANK: factory = new TankFactory(); break; case ARMOURED_CAR: factory = new ArmouredCarFactory(); break; // case clauses for the rest of the factories } // Create the vehicle's components. Chassis chassis = factory.createChassis(); Body body = factory.createBody(); Weapons weapons = factory.createWeapons(); Armour armour = factory.createArmour(); // Checking what the factory has created. System.out.println(chassis.getChassisParts()); System.out.println(body.getBodyParts()); System.out.println(weapons.getWeaponsParts()); System.out.println(armour.getArmourParts()); } } // end of class
Points to Consider about the Abstract Factory Pattern
We should think about implementing an abstract factory when we have a class with a set of factory methods that obscure its primary responsibility. Each class should only have a single responsibility. When a class deals with multiple product types, it might be worth moving its factory methods into a stand-alone factory class or a full-blown abstract factory implementation.
During application design, we must always consider whether we really need a factory. Using a factory adds complexity to our application, which may or may not be necessary. The code may become more complicated than it should be, since a lot of new interfaces and classes are introduced along with the pattern.
What’s next?
In the weeks ahead, we’ll continue examining some of the more useful design patterns. Stay tuned!
As always, please share your comments and questions. And if you’ve enjoyed this, then please subscribe to our Java Tips and receive a free tip in your inbox every week!