Factory Method Pattern
The factory method pattern provides a way for decoupling object creation, where subclasses determine the types of objects that will be created. Instead of creating objects in the high-level code via 'new,' the pattern delegates creation to subclasses through an inherited interface or abstract factory method instead. This hides the 'new' construction logic from the high-level class. Implementations of the factory method in subclasses can now return any type of concrete object implemented from the abstraction.
In the below example, note how the high-level CampaignSetup function setupCampaign() does not care what type of OwnerBuilder it is calling register() on. Note also how the desired type of OwnerBuilder class is not determined until runtime in test.php, showing decoupling of the type of OwnerBuilder from CampaignSetup, and allowing great flexibility.

//CampaignSetup.php
require_once 'OwnerBuilder.php';
abstract class CampaignSetup{
protected $ownerBuilder;
protected abstract function createOwnerBuilder();
protected function initializeCampaign(){
echo "initializing campaign\n";
}
protected function addInventory(){
echo "adding inventory\n";
}
protected function registerOwner(){
$this->ownerBuilder->register();
}
public function setupCampaign(){
$this->initializeCampaign();
$this->addInventory();
$this->ownerBuilder->register();
echo "\nCampaign Setup Complete\n\n";
}
}
//AdvancedCampaignSetup.php
require_once 'CampaignSetup.php';
require_once 'AdminOwnerBuilder.php';
class AdvancedCampaignSetup extends CampaignSetup{
public function __construct(){
$this->createOwnerBuilder();
}
protected function createOwnerBuilder(){
$this->ownerBuilder = new AdminOwnerBuilder();
}
}
//LimitedCampaignSetup.php
require_once 'CampaignSetup.php';
require_once 'StandardOwnerBuilder.php';
class LimitedCampaignSetup extends CampaignSetup{
public function __construct(){
$this->createOwnerBuilder();
}
protected function createOwnerBuilder(){
$this->ownerBuilder = new StandardOwnerBuilder();
}
}
//OwnerBuilder.php
abstract class OwnerBuilder{
protected $id;
protected function addOwner($id){
echo "Adding owner id: $id\n";
$this->id = $id;
}
public abstract function register();
}
//AdminOwnerBuilder.php
require_once 'OwnerBuilder.php';
class AdminOwnerBuilder extends OwnerBuilder{
private function grantAdmin($id){
echo "Giving owner $id admin rights";
$this->id = $id;
}
public function register(){
$id = readline("Enter owner id to add: ");
$this->addOwner($id);
if(readline("Grant owner admin rights?
Please enter true or false: ") == 'true')
$this->grantAdmin($id);
}
}
//StandardOwnerBuilder.php
require_once 'OwnerBuilder.php';
class StandardOwnerBuilder extends OwnerBuilder{
public function register(){
$id = readline("Enter owner id to add: ");
$pass = readline("Enter standard campaign creation password: ");
if($pass == 'pass182sS29exm')
$this->addOwner($id);
else
throw new Exception("Bad password for standard campaign setup")
}
}
//test.php
require_once 'AdvancedCampaignSetup.php';
require_once 'LimitedCampaignSetup.php';
$campaignSetup;
echo "Starting campaign setup\n";
$campType = readline("Setup limited or advanced campaign?
Please enter standard or advanced: ");
switch($campType){
case 'standard':
$campaignSetup = new LimitedCampaignSetup();
break;
case 'advanced':
$campaignSetup = new AdvancedCampaignSetup();
break;
default:
throw new Exception("Invalid Campaign Setup type");
}
$campaignSetup->setupCampaign();