Factory Design Pattern

Factory Design Pattern

In this post, I’m going to talk about a design pattern; a design pattern is something you can use to solve common problems. I’m going to cover a simple example of the “factory design pattern” and an example that is a little more complicated in another post. This concept may be a bit difficult to wrap your mind around, but it’s worth it in the end.

For the simple example, we will pretend we are developing an e-commerce solution for a t-shirt we designed. We designed and printed this awesome shirt; our friends love it, and we are going to sell a ton. We will start off with our AwesomeShirt class.


<?php
class AwesomeShirt {
    public function order() {
        echo 'Awesome shirt order placed.';
    }

    public function ship() {
        echo 'Awesome shirt order shipped.';
    }

    public function returnOrder() {
        echo 'Awesome shirt order returned.';
    }
}

Okay, that’ll work, but what if we become successful and people want us to make some different shirts? Let’s rethink this and refactor.


<?php
class ShirtFactory {
    public static function build($shirtType = null) {
        if($shirtType == null) {
            throw new Exception('Must Pass a Shirt Type.');
        }

        $shirtClass = ucfirst($shirtType) . 'Shirt';

        if(class_exists($shirtClass)) {
            return new $shirtClass;
        }

        throw new Exception('Invalid Shirt Type.');
    }
}

interface ShirtType {
    public function order();
    public function ship();
    public function returnOrder();
}

class AwesomeShirt implements ShirtType {
    public function order() {
        echo 'Awesome shirt order placed.';
    }

    public function ship() {
        echo 'Awesome shirt order shipped.';
    }

    public function returnOrder() {
        echo 'Awesome shirt order returned.';
    }
}

class FunnyShirt implements ShirtType {
    public function order() {
        echo 'Funny shirt order placed.';
    }

    public function ship() {
        echo 'Funny shirt order shipped.';
    }

    public function returnOrder() {
        echo 'Funny shirt order returned.';
    }
}

$shirt = ShirtFactory::build('Awesome');
$shirt->order(); // OUTPUT: Awesome shirt order placed.

Okay, what happened? Well, we created a ShirtFactory class that can build() different kinds of shirts.

We then created two types of shirts that implemented the ShirtType interface, which allows us to pass those to our factory method build. If we ever need to make any more types of shirts, we can.

Do you see anything that we’ve repeated and could maybe simplify? Well, all shirts can be ordered, shipped, and returned. Each of those methods echoes out the name and the action. Let’s create an abstract class to handle the work for us.


<?php
interface ShirtType {
    public function order();
    public function ship();
    public function returnOrder();
}

abstract class Products implements ShirtType {
    protected $name;

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

    public function order() {
        echo $this->name . ' shirt order placed.';
    }

    public function ship() {
        echo $this->name . ' shirt order shipped.';
    }

    public function returnOrder() {
        echo $this->name . ' shirt order returned.';
    }
}

class AwesomeShirt extends Products implements ShirtType {
    
}

class FunnyShirt extends Products implements ShirtType {
    
}

class ShirtFactory {
    public static function build($shirtType = null) {
        if($shirtType == null) {
            throw new Exception('Must Pass a Shirt Type.');
        }

        $shirtClass = ucfirst($shirtType) . 'Shirt';

        if(class_exists($shirtClass)) {
            return new $shirtClass($shirtType);
        }

        throw new Exception('Invalid Shirt Type.');
    }
}

$shirt = ShirtFactory::build('Awesome');
$shirt->order(); // OUTPUT: Awesome shirt order placed.

So, what did we do? Well, we removed the methods from the concrete classes AwesomeShirt and FunnyShirt and put them in our abstract class Product. When we use the build() method in the ShirtFactory class, we instantiate the class for that shirt and pass the name of it to the construct, which then sets the $name property. When we run ShirtFactory::build('Awesome'); it returns a new AwesomeShirt. We are then able to call the different methods for that class, such as order() as I did in the example above.

In the next post about this design pattern, I’ll use reflection to do some really neat things. PHP has come a long way since I first started writing it and I feel like more great things are to come. If you have any questions, comments, or corrections; please email me. I’m happy to help others learn.

If none of it made any sense; take a nap and try again later. If you read it again and still don’t understand, it’s okay, don’t get frustrated. I’ll keep writing more posts, and you’ll learn it one day. Keep reading and practicing.