Your Guide to Design Patterns – Abstract Factory Pattern

Design Patterns - Abstract Factory Pattern

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 ,ChassisWindowsArmourWeapons, 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!

Leave a Comment

Your email address will not be published. Required fields are marked *

Code like a Java Guru!

Thank You

We're Excited!

Thank you for completing the form. We're excited that you have chosen to contact us about training. We will process the information as soon as we can, and we will do our best to contact you within 1 working day. (Please note that our offices are closed over weekends and public holidays.)

Don't Worry

Our privacy policy ensures your data is safe: Incus Data does not sell or otherwise distribute email addresses. We will not divulge your personal information to anyone unless specifically authorised by you.

If you need any further information, please contact us on tel: (27) 12-666-2020 or email info@incusdata.com

How can we help you?

Let us contact you about your training requirements. Just fill in a few details, and we’ll get right back to you.

Your Java tip is on its way!

Check that incusdata.com is an approved sender, so that your Java tips don’t land up in the spam folder.

Our privacy policy means your data is safe. You can unsubscribe from these tips at any time.