The Factory Pattern

0
733
Factory pattern

In this short article, we take a look at a common pattern in software design called the Factory pattern.

By using the Factory pattern early on in your software development, you get in the habit of creating objects through a standard means. The additional benefit is that you if you need to modify your object instantiation code, you can do it without rewrites.

On The Fly Object Instantiation

At runtime, you make decisions about what objects to instantiate. The code you write may look a little like this:

  1. switch($type) {
  2.   case "Truck":
  3.     $v = new Truck();
  4.     break;
  5.   case "Motorycle":
  6.     $v = new Motorcycle();
  7.     break;
  8.   case "Car":
  9.     $v = new Car();
  10.     break;
  11. }

Or, with a series of if-then statements like this:

  1. if ($type == "Truck")
  2.   $v = new Truck();
  3. else if ($type == "Motorycle")
  4.   $v = new Motorcycle();
  5. else if ($type == "Car")
  6.   $v = new Car();
  7. }

If this code is scattered throughout your entire application, it can be a nightmare to support. Especially if you need to make changes. Imagine this being in a dozen or more source files in your project. Every time you need to make a change to this code by adding or removing class types, you have to modify it in those dozen or so files. A better way of handling this is to create one source file that wraps the switch statement and series of if-then statements.

  1. function CreateObj($type) {
  2.   $obj = NULL;
  3.   switch($type) {
  4.     case "Truck":
  5.       $obj = new Truck();
  6.       break;
  7.     case "Motorycle":
  8.       $obj = new Motorcycle();
  9.       break;
  10.     case "Car":
  11.       $obj = new Car();
  12.       break;
  13.   }
  14.   return($obj);
  15. }

Then you call it like so with different syntactic sugar:

  $car = CreateObj("Car");
  $truck = CreateObj("Truck");
  $cycle = CreateObj("Motorcycle");

By centralizing your object creation, you make it much more easier to support and adapt. But this in and of itself isn’t the factory pattern. Lets tweak this to be more object oriented.

The Factory Pattern OOP

Rather than a function to create objects, we can create a class that is a Widget factory. Inside this class, you have a static function that wraps your programming language’s ability to create objects – typically via ‘new’.

In the code written in PHP below, we take advantage of several run time functions that check to see if a class of a certain name exists. We also create on-the-fly an object given a string class name. The creation of Widgets are done within the static Create method.

  1. class WidgetFactory {
  2.   public static function Create($classname, $widgetName) {
  3.     if (FALSE == class_exists($classname)) {
  4.       throw new Exception("WidgetFactory: Cannot create object. Class $classname does not exist.");
  5.     }  
  6.     $obj = new $classname($widgetName);
  7.     return($obj);
  8.   }
  9. }

Suppose we want to create unique identifiers and names for all our widgets so we can track them. Using the WidgetFactory class above, here’s how you can implement this.

  1. function EchoLine($str, $html=true) {
  2.   $out = ($html) ? $str . "<br>" : $str . "\n";
  3.   echo $out;
  4. }
  5.  
  6. class Widget {
  7.   private $guid;
  8.   private $name;
  9.   private $id;
  10.  
  11.   public function __construct($widgetName) {
  12.     $this->name = $widgetName;
  13.     $this->guid = $this->CreateGUID();
  14.     $this->id = $this->name . "_" . $this->guid;
  15.   }
  16.   private function CreateGUID() {
  17.     $randStr = md5(uniqid(rand(),true)); 
  18.     $randStr = strtoupper($randStr);
  19.     $guid = '{';
  20.     $guid .= substr($randStr,0,8);
  21.     $guid .= '-';
  22.     $guid .= substr($randStr,8,4);
  23.     $guid .= '-';
  24.     $guid .= substr($randStr,12,4);
  25.     $guid .= '-';
  26.     $guid .= substr($randStr,16,4);
  27.     $guid .= '-';
  28.     $guid .= substr($randStr,20);
  29.     $guid .= '}'; 
  30.     return($guid);
  31.   }
  32.   public function GetGUID() {
  33.     return($this->guid);
  34.   }
  35.   public function GetName() {
  36.     return($this->name);
  37.   }
  38.   public function GetId() {
  39.     return($this->id);
  40.   }
  41. }

And here’s how you create Widgets:

  1. try {
  2.   $blueWidget = WidgetFactory::Create("Widget","Blue");
  3.   EchoLine($blueWidget->GetId());
  4.   $redWidget = WidgetFactory::Create("Widget","Red");
  5.   EchoLine($redWidget->GetId());
  6.   $greenWidget = WidgetFactory::Create("Widget","Green");
  7.   EchoLine($greenWidget->GetId());
  8.   $badWidget = WidgetFactory::Create("Bad","BadWidget");
  9. } catch(Exception $e) {
  10.   EchoLine($e->getMessage());
  11. }