Design Patterns Made Easy – Factory Pattern

Factory Pattern

Factory Pattern helps to instantiate complex objects keeping future changes in mind. In this case, you don’t use the new keyword to directly instantiate an object of a class, but use a static method of another factory class. This helps to wrap up complex and dynamic construction of objects or helps in cases where the right class to instantiate depends on input parameters.


class Person {
	private $name;
	protected $type;

	function __construct($_name, $_type) {
		$this->name = $_name;
		$this->type = $_type;
	}
}

interface iPerson {
	function behave();
}

class Good_Person extends Person implements iPerson {
	protected $type;

	function __construct($_name) {
		$this->name = $_name;
		$this->type = "GOOD";
	}

	function behave() {
		echo $this->name." is a ".$this->type." person!";
	}
}

class Bad_Person extends Person implements iPerson {
	protected $type;

	function __construct($_name) {
		$this->name = $_name;
		$this->type = "BAD";
	}

	function behave() {
		echo $this->name." is a ".$this->type." person!";
	}
}

class PersonFactory {
	function create($name, $type) {
		$type = ucwords(strtolower($type));
		$class = $type."_Person";
		if (class_exists($class)) {
			return new $class($name);
		} else {
			throw new Exception("Invalid type");
		} 
	}
}

$type_of_person = "GOOD"; //This could be $_POST['person_type']
$good_person = PersonFactory::create("Floyd", $type_of_person);
$good_person->behave();

Now the construction logic has been separated to the Factory class and therefore the code is much more flexible and maintainable in the long run. If the logic behind instantiating the object changes at some point, all we need to do is update the factory create method and leave the rest of the code as they were.

Design Patterns Made Easy – Revisit OOP Concepts

This is the first article in a series with objective to make design patterns understandable to everybody having basic OOP concepts. With so many different languages, frameworks available and emerging every now and then, its very important to have mastered the fundamentals of good programming practices than trying to work out every new language or frameworks. Design Patterns help you to tackle common architectural issues and encourage best practices to provide long term manageability to your application. This series assume you have basic understanding of OOP concenpts i.e class, object, inheritance, scope, interface etc. Don’t worry if you can’t remember all of them, we will revisit some of these in this article, specially those important for understanding the design patterns.

If you’d like to see all the articles in this series, please click here.

Visibility

Visibility of a property or method can be defined as public, private or protected. It defaults to public.

Public

This makes a property or method available from anywhere, within the class, derived objects and extended classes.

Private

This makes a property or method available from only within the class. Derived objects will not have access to these properties or methods directly but can use public getters (will be explained later) to gain indirect access.

Protected

This makes a property or method available from within the class or any class which extends it.


class Person {
  public $name;
  public $age;
  protected $type;
  private $id;

  //Constructor that receives the name, age, type and sets the object properties
  public function __construct($_name, $_age, $_type) {
    $this->name = $_name;
    $this->age = $_age;
    $this->type = $_type;
    $this->id = uniqid();
  }

  //Getter for $type
  public function getType() {
    return $this->type;
  }

  //Getter for $id
  public function getID() {
    return $this->id;
  }
}

class Student extends Person {
  public $student_id;

  //We can redeclare private and protected properties, but not private
  protected $type;

  public function __construct($_name, $_age, $_type) {
    $this->name = $_name;
    $this->age = $_age;
    $this->type = $_type;
  }
}

$person = new Person("Floyd", "28", "PERSON");

//Will display Fatal Error: Cannot access private property Person::$id
//echo $person->id;

//Will display Fatal error: Cannot access protected property Person::$type
//echo $person->type;

//Will display something like 55123095e0161
echo $person->getID();

$student = new Student("Floyd", "28", "STUDENT");

//Will display STUDENT
echo $student->getType();

Static

If a property or a method of a class has been declared static, this means, this property or method can be accessed without initializing an object of that class. Please note that $this is not available since there is no object instantiated. Instead Scope Resolution operator (::) has to be used.


class Utility {
  public static $last_result;
  public static function add($num_array, $append = false) {
    if ($append) {
      self::$last_result += array_sum($num_array);
    } else {
      self::$last_result = array_sum($num_array);
    }
    return self::$last_result;
  }
}

//Will display 15
echo Utility::add([1, 2, 3, 4, 5]);

//Will display 30
echo Utility::add([1, 2, 3, 4, 5], true);

Utility::add([1, 2, 3], false);

//Will display 6
echo Utility::$last_result;

Interface and Abstract classes

Interface

An interface is a facade for a class. It is a blue-print which dictates how the class will look like. Interfaces can not be instantiated and must be implemented. Interfaces do not define the behaviors but defines what those behaviors are. You must implement your own behaviors by implementing interfaces in a class.


//Interface IPerson defines what a Person class can do
interface IPerson {
  public function eat($food);
  public function sleep($hours);
  public function walk($miles);
}

class Person implements IPerson {
  private $name;

  public function __construct($_name) {
    $this->name = $_name;
  }

  //Person class must define the behaviors mentioned in IPerson interface i.e eat(), sleep() and walk()
  public function eat($food) {
    echo $this->name." eats ".$food.".
";
  }

  public function sleep($hours) {
    echo $this->name." sleeps for ".$hours." hours.
";
  }

  public function walk($miles) {
    echo $this->name." walks ".$miles." miles everyday!
";
  }
}

$person = new Person("Floyd");
$person->eat("Pizza");
$person->sleep(6);
$person->walk(5);

//Output:
//Floyd eats Pizza.
//Floyd sleeps for 6 hours.
//Floyd walks 5 miles everyday!

Abstract Class

Abstract classes can not be instantiated but can be extended. It can contain empty methods as well as well defined methods if you’d like all the classes that extends it to have some common behaviors. Lets take a look at the above exmaple re-written with Abstract class instead of an Interface.


abstract class Person {
  //Scope changed from private to protected to allow access from child classes
  protected $name;

  public function __construct($_name) {
    $this->name = $_name;
  }

  public function eat($food) {
    echo $this->name." eats ".$food.".";
  }

  public function sleep($hours) {
    echo $this->name." sleeps for ".$hours." hours.";
  }

  public function walk($miles) {
    echo $this->name." walks ".$miles." miles everyday!";
  }
}

class GoodPerson extends Person {
  //All classes which extend Person will have default eat(), sleep() and walk() methods.
  //Lets define a donate() method in addition
  public function donate($money) {
    echo $this->name." donates ".$money."$ to charity!";
  }
}

//Will show Fatal error: Cannot instantiate abstract class Person
//$person = new Person();

$person = new GoodPerson("Floyd");
$person->eat("Pizza");
$person->sleep(6);
$person->walk(5);
$person->donate(10);

//Output:
//Floyd eats Pizza.
//Floyd sleeps for 6 hours.
//Floyd walks 5 miles everyday!
//Floyd donates 10$ to charity!

That’s it for today. In the next post I will start explaining the most important Design Patterns one by one. Keep in touch! If you have any question or suggestion, please comment below.

Next Article: Factory Pattern