Simple Factory Pattern
What is a factory? Let’s imagine you order a new car; the dealer sends your order off to the factory and the factory builds your car. Your car is sent to you in its assembled form and you don’t need to care about how it was made.
Similarly, a software factory produces objects for you. The factory takes your request, assembles the object using the constructor and gives them back to you to use. One of these types of Factory pattern is known as the Simple Factory. Let me show you how it works.
Firstly, we define an abstract class, which we want to extend with other classes:
<?php
abstract class Notifier
{
protected $to;
public function __construct(string $to)
{
$this->to = $to;
}
abstract public function validateTo(): bool;
abstract public function sendNotification(): string;
}
This class serves to allow us to have common methods and define whatever common functionality we want all the classes we build in our factory to have in common. We could also use interfaces instead of abstract classes for the implementation without defining any functionality whatsoever.
Using this interface, we can build two notifiers, SMS
and Email
.
The SMS
notifier is as follows in the SMS.php
file:
<?php
class SMS extends Notifier
{
public function validateTo(): bool
{
$pattern = '/^(\+44\s?7\d{3}|\(?07\d{3}\)?)\s?\d{3}\s?\d{3}$/';
$isPhone = preg_match($pattern, $this->to);
return $isPhone ? true : false;
}
public function sendNotification(): string
{
if ($this->validateTo() === false) {
throw new Exception("Invalid phone number.");
}
$notificationType = get_class($this);
return "This is a " . $notificationType . " to " . $this->to . ".";
}
}
Similarly, let’s put out Email
notifier in the Email.php
file:
<?php
class Email extends Notifier
{
private $from;
public function __construct($to, $from)
{
parent::__construct($to);
if (isset($from)) {
$this->from = $from;
} else {
$this->from = "Anonymous";
}
}
public function validateTo(): bool
{
$isEmail = filter_var($this->to, FILTER_VALIDATE_EMAIL);
return $isEmail ? true : false;
}
public function sendNotification(): string
{
if ($this->validateTo() === false) {
throw new Exception("Invalid email address.");
}
$notificationType = get_class($this);
return "This is a " . $notificationType . " to " . $this->to . " from " . $this->from . ".";
}
}
So now we can build our factory as follows:
<?php
class NotifierFactory
{
public static function getNotifier($notifier, $to)
{
if (empty($notifier)) {
throw new Exception("No notifier passed.");
}
switch ($notifier) {
case 'SMS':
return new SMS($to);
break;
case 'Email':
return new Email($to, 'XYZ');
break;
default:
throw new Exception("Notifier invalid.");
break;
}
}
}
Lets put this all together in index.php
file
<?php
require_once('Notifier.php');
require_once('NotifierFactory.php');
require_once('SMS.php');
$mobile = NotifierFactory::getNotifier("SMS", "07111111111");
echo $mobile->sendNotification(); // Output: This is a SMS to 07111111111
require_once('Email.php');
$email = NotifierFactory::getNotifier("Email", "test@example.com");
echo $email->sendNotification(); // Output: This is a Email to test@example.com from XYZ
That’s how the factory pattern works. But there’s one problem with this pattern. Lets say in future you implement another notifier Voice Call
, then to adopt this new change we have to modify our NotifierFactory
class. And it will be a violation of Open-Closed Principle. To avoid that we can use Factory Method Pattern
which will be discussed in a later post.