TailTemplate Build stunning websites faster with our pre-designed Tailwind CSS templates

Understanding Design Patterns - Abstract Factory

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

Business is bombing at Dragon Inc. and the CEO wants to franchise all overseas branches. The first problem that comes to his attention is how they can ensure the quality of the products. They do not want franchisees to cut costs and use low quality components. Low quality toys would definitely destroy Dragon brand’s reputation. So, the CEO wants to franchise the business, but they still want to have factories located in each location to provide components. Developers gather and start to brainstorm solutions. There are three types of components used by toys; engines, wheels and rotor blades. For example, a toy car needs an engine and four wheels, while a toy helicopter uses a rotor blade and an engine.

Let us first create an abstract factory class, the back bone of all concrete factories. Note that the abstract factory essentially consists of a group of factory methods:

abstract class ComponentsFactory
{
    abstract function createEngine() ;
    abstract function createWheel() ;
    abstract function createRotorBlade() ;
}

Then create a location specific factory (The concrete factory for creating concrete components). Let us create one for New York:

class NyComponentsFactory extends ComponentsFactory
{
 
    public function createEngine()
    {
        return new NyEngine();
    }
 
    public function createWheel()
    {
        return new NyWheel();
    }
 
    public function createRotorBlade()
    {
        return new NyRotorBlade();
    }
}

The Toy class also needs to be modified. Engines, wheels and rotor blades need to be clarified, and prepare() function needs to be abstract (This method will be implemented by a concrete class. In the implementation, a child class uses its location specific ComponentsFactory to create concrete components). Modify Toy class:

abstract class Toy {
    public $name    = '';
    public $price   = 0;
    public $engine  = null;
    public $wheels  = array();
    public $rotorBlade = null;
    abstract function prepare() ;
    public function package()
    {
        echo $this->name. ' is packaged';
    }
 
    public function label()
    {
        echo $this->name . ' is priced at '.$this->price;
    }
}

Let's modify the NyCar and NyHelicopter classes to implement prepare() method.

class NyCar extends Toy
{
    public $name  = 'NyCar';
    public $price = 30;
    public $componentsFactory = null;
    public function  __construct(ComponentsFactory $componentsFactory)
    {
        $this->componentsFactory = componentsFactory;
    }
 
    public function prepare()
    {
        $this->engine   = $this->componentsFactory->createEngine();
        $this->wheels[] = $this->componentsFactory->createWheel();
        $this->wheels[] = $this->componentsFactory->createWheel();
        $this->wheels[] = $this->componentsFactory->createWheel();
        $this->wheels[] = $this->componentsFactory->createWheel();
    }
}
 
class NyHelicopter extends Toy
{
    public $name  = 'NyCar';
    public $price = 30;
    public $componentsFactory = null;
 
    public function  __construct(ComponentsFactory $componentsFactory)
    {
        $this->componentsFactory = componentsFactory;
    }
 
    public function prepare()
    {
        $this->engine      = $this->componentsFactory->createEngine();
        $this->rotorBlade  = $this->componentsFactory->createRotorBlade();
    }
}

Lastly factory method of concrete ToysFactory needs to be modified. This is where to added location specific ComponensFactory. Let's complete the code for NyToysFactory:

class NyToysFactory extends ToysFactory
{
    public function createToy($toyName)
    {
        $toy = null;
        $nyComponentsFactory = new NyComponentsFactory();
        if ('car'==$toyName) {
            $toy = new NyCar($nyComponentsFactory);
        } else if ('helicopter'==$toyName) {
            $toy = new NyHelicopter($nyComponentsFactory);
        }
        return $toy;
    }
}

Now each franchise will have their components supplied by a component factory, which is controlled by Dragon Inc. HQ.

Throughout the course, we've built a franchise framework, giving Dragon Inc. control and enough freedom for each franchise to do what they're good at.

The end

Hopefully this simple tutorial helped you with your development. If you like our post, please follow us on Twitter and help spread the word. We need your support to continue. If you have questions or find our mistakes in above tutorial, do leave a comment below to let us know.