Posted by Keyvan Akbary on Dec 08, 2014

Factory pattern

The Factory pattern is probably the most used design pattern in modern programming development today. The pattern can be considered a variation of the Factory Method and Abstract Factory creational patterns defined in the Gang of Four, it allows you to decouple your business logic from instantiation logic.

Creates objects without exposing the instantiation logic to the client

To better understand this pattern, let us take a look at the following contrived example.

class VendingMachine {
    public function infoFor($code) {
        $description = '';
        $price = '';
        if ($code === 0) {
            $description = 'delicious chocolate';
            $price = 1;
        } elseif ($code === 1) {
            $description = 'crunchy chips';
            $price = 1.2;
        } elseif ($code === 3) {
            $description = 'tasty sandwich';
            $price = 2.5;
        }

        return $this->format($description, $price);
    }

    private function format($description, $price) {
        return
            'description: ' . $description . "\n" .
            'price: ' . $price . ' euros';
    }
}

$m = new VendingMachine;
echo $m->infoFor(1);
// description: crunchy chips
// price: 1.2 euros

Looking at this implementation we notice a couple of problems. A vending machine provides you with snacks, however, there is no concept in the system that matches these related parts.

A snack is represented by a description and a price. These two pieces of data are scattered all over the implementation without any unity. It also looks strange that the method responsible for showing snack information is also responsible for creating them too. Attempting to add a new property, changing the behavior or trying to reuse the code elsewhere will complicate matters even more so.

With these issues in mind we could define a common interface for all the snacks.

interface Snack {
    public function description();
    public function price();
}

class Chocolate implements Snack {
    public function description() {
        return 'delicious chocolate';
    }

    public function price() {
        return 1;
    }
}

class Chips implements Snack {
    public function description() {
        return 'crunchy chips';
    }

    public function price() {
        return 1.2;
    }
}

class Sandwich implements Snack {
    public function description() {
        return 'tasty sandwich';
    }

    public function price() {
        return 2.5;
    }
}

Now the implementation is starting to look better.

class VendingMachine {
    public function infoFor($code) {
        $snack = null;
        if ($code === 0) {
            $snack = new Chocolate;
        } elseif ($code === 1) {
            $snack = new Chips;
        } elseif ($code === 3) {
            $snack = new Sandwich;
        }

        return $this->format($snack);
    }

    private function format(Snack $snack) {
        return
            'description: ' . $snack->description() . "\n" .
            'price: ' . $snack->price() . ' euros';
    }
}

We still have the problem however, in that the instantiation code-logic is tightly coupled to the show information logic. This means that the only way of adding a new product is adding a new elseif to this method.

It goes without question that showing information is a different responsibility to creating it.

Decoupling instantiation logic

By using the Factory pattern, we could easily extract this instantiation logic into a dedicated class.

class SnackFactory {
    public function create($code) {
        switch($code) {
            case 0:
                return new Chocolate;
            case 1:
                return new Chips;
            case 2:
                return new Sandwich;
        }

        throw new Exception('No snack for code ' . $code);
    }
}

Now the client code is free from the problems faced in the snack catalog.

class VendingMachine {
    private $snackFactory;

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

    public function infoFor($code) {
        return $this->format($this->snackFactory->create($code));
    }

    private function format(Snack $snack) {
        return
            'description: ' . $snack->description() . "\n" .
            'price: ' . $snack->price() . ' euros';
    }
}

Adding, modifying or removing a snack from the catalog is now as easy as updating the Factory. Changes in the catalog will not require any modifications in the vending machine. Now the instantiation logic is completely decoupled from the business logic. As such they can now evolve independently of each other.

Testing

Another positive result from this separation is that, now we can replace the Factory with a test double in order to force a concrete flow in the System Under Test.

class VendingMachineTest extends PHPUnit_Framework_TestCase {
    /**
     * @test
     */
    public function itShouldComposeSnackInfo() {
        $vendingMachine = new VendingMachine(
            $this->createSnackFactoryStubWith(new SnackStub)
        );
        
        $expected = <<<INFO
description: irrelevant
price: 0 euros
INFO;

        $this->assertEquals($expected, $vendingMachine->infoFor(0));
    }

    private function createSnackFactoryStubWith($snack) {
        $stub = Mockery::mock('SnackFactory');
        $stub->shouldReceive('create')->andReturn($snack);

        return $stub;
    }
}

class SnackStub implements Snack {
    public function description() {
        return 'irrelevant';
    }

    public function price() {
        return 0;
    }
}

There is no need to couple the test with a real snack instance. The test asserts that the information provided by the vending machine is only formated correctly. As a result we could use instead a simple Stub for this case.

Jobs at MyBuilder

We need an experienced software engineer who loves their craft and wants to share their hard-earned knowledge.

View vacancies
comments powered by Disqus