Design patterns are repeatable solutions to commonly occurring problems in software design. Sure, they’re not terribly interesting (or easy to learn as a result), but they can make life a lot easier. We’re taking on the challenge of making one set of design patterns easy (and interesting!) to learn with the help of a fictional case study about a toy company. Before we get started, however, let’s go over what we’ll cover.
We’ll be focusing on a family of design patterns we call Factory Patterns. The group includes the Simple Factory, Factory Method and Abstract Factory patterns:
- Simple Factory: Strictly speaking, it’s not a design pattern, but a technique we use very often. It encapsulates the object instantiation process.
- Factory Method: Defines an interface for creating an object, but let’s the classes that implement the interface decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses.
- Abstract Factory: Provides an interface for creating families of related or dependent objects without specifying their concrete classes.
You will need to have some basic object-oriented programming knowledge (Encapsulation, data abstraction, polymorphism and inheritance) and familiarity with PHP to work through this tutorial.
Let’s get started! And so begins the tale of our fictional toy company…
Simple Factory
> I’m not really a design pattern, but hey, I’m useful.
Dragon Inc. is one of the top toy manufacturers in China. In fact, they’re a pioneer in toy manufacturing. They started production at a time when few toys were being produced commercially. Hence, they dominated the market and became the leader in the toy production industry.
Their produceToy()
function looked like this:
class ToysFactory {
public function produceToy($toyName) {
$toy = null;
if ('car'==$toyName) {
$toy = new Car();
} else if ('helicopter'==$toyName) {
$toy = new Helicopter();
}
$toy->prepare();
$toy->package();
$toy->label();
return $toy;
}
}
Initially, they only manufactured toy Cars
and Helicopters
. For this simple task the function worked well and everyone was happy. But not long after that, a cool new toy, the “Jumping Frog,” was introduced by the design team. Jumping Frog looked cool and they knew it was going to sell really well, it was time to change the produceToy()
function:
class ToysFactory {
public function produceToy($toyName) {
$toy = null;
if ('car'==$toyName) {
$toy = new Car();
} else if ('helicopter'==$toyName) {
$toy = new Helicopter();
} else if ('jumpingFrog'==$toyName) {
$toy = new JumpingFrog();
}
$toy->prepare();
$toy->package();
$toy->label();
return $toy;
}
}
As the business grew, more and more toys came into production and the CEO was very happy with the business’ financial growth. However, the development team’s office the nightmare was just beginning. The developers were tasked to modify the produceToy()
function with the introduction of every new toy. It has violated the open/close principle. Which states “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”. Every new toy brought in modifications of the produceToy()
function.
It was time for refactoring. 
Let’s take a look at the situation here. What was the real issue with produceToy
function? A concrete class was instantiated inside ToysFactory
and messed up the produceToy()
function. The ToysFactory
class was tied to the concrete classes of toys. Let’s the issue.
First, let’s create a class to encapsulate the concrete class instantiation.
class SimpleFactory {
public function createToy($toyName) {
$toy = null;
if ('car'==$toyName) {
$toy = new Car();
} else if ('helicopter'==$toyName) {
$toy = new Helicopter();
}
return $toy;
}
}
Second, we’ll use SimpleFactory
to create the desired toys:
class ToysFactory {
public $simpleFactory;
public function __construct(SimpleFactory $simpleFactory) {
$this->simpleFactory = $simpleFactory;
}
public function produceToy($toyName) {
$toy = null;
$toy = $this->simpleFactory->createToy($toyName);
$toy->prepare();
$toy->package();
$toy->label();
return $toy;
}
}
With our brand new class SimpleFactory
, things just became uncomplicated. The devs no longer need to touch ToysFactory
when a new toy is introduced, and they’ll just use SimpleFactory
to produce a new toy instead of using the former messy code.
This is the Simple Factory. It’s not a real design pattern per se, but it’s a useful technique that you can apply to your own needs. With Simple Factory, concrete class instantiation is encapsulated. It decouples the client code from the object creation code.
Factory Method
> Defines an interface for creating an object, but lets classes that > implement the interface decide which class to instantiate. The Factory > method lets a class defer instantiation to subclasses.
With the Simple Factory in place, developers are now enjoying their day at Dragon Inc. Despite the thorough discussion of toys, we haven’t really looked at the toy classes yet. Toy
is an abstract class with the functions prepare()
, package()
and label()
.
abstract class Toy {
public $name = '';
public $price = 0;
public function prepare() {
echo $this->name. ' is prepared';
}
public function package() {
echo $this->name. ' is packaged';
}
public function label(){
echo $this->name . ' is priced at '.$this->price;
}
}
The concrete classes Car
and Helicopter
inherit from super class Toy
. They’re pretty straightforward.
Car:
class Car extends Toy {
public $name = 'Car';
public $price = 20;
}
Helicopter:
class Helicopter extends Toy {
public $name = 'Helicopter';
public $price = 100;
}
Back to Dragon Inc. The CEO walks in to the developers’ office with a smile on his face, but we know there’s bad news coming. The CEO happily announces that Dragon Inc. is going to open several factories in the US. They’ll be located in different states, and the first two will be in New York and California. All toys will be produced locally with their own properties, which means that for the same type of toy Car, the ones produced in New York will be NyCar
and those from California will be CaCar
. Simple Factory will make this task a cinch for the development team. All they need to do is create a location specific SimpleFactory
class and a location specific ToysFactory
class. Simple Factory simplifies the task and makes the developers’ job easy.
For example, for New York we could do:
class NySimpleFactory {
public function createToy($toyName) {
$toy = null;
if ('car'==$toyName) {
$toy = new NyCar();
} else if ('helicopter'==$toyName) {
$toy = new NyHelicopter();
}
return $toy;
}
}
class NyToysFactory {
public $simpleFactory;
public function __construct(SimpleFactory $simpleFactory) {
$this->simpleFactory = $simpleFactory;
}
public function produceToy($toyName) {
$toy = null;
$toy = $this->simpleFactory->createToy($toyName);
$toy->prepare();
$toy->package();
$toy->label();
return $toy;
}
}
The developers finish the new code quickly and hand it over to the US factories. After two weeks, the phone starts ringing in the developers’ office because the New York factory was having production issues. It turns out that the NyToysFactory
class has been modified by developers at the remote branch because the staff doesn’t want to do packaging and labeling work. They’ve modified produceToy()
by removing its label()
and package()
functions.
It seems like Simple Factory won’t work in this scenario. We don’t want branches in US to be able to modify produceToy()
functions. ProduceToy()
should consist of a set of standard procedures and the branches should only be responsible for creating location specific toys. What if they can create an abstract class? And the abstract class they create will have a concrete produceToy()
method which will implement a set of standard operating procedurea that all branches have to follow. Inside produceToy()
, it calls its own abstract method createToy()
to obtain a toy class. This way createToy()
is able to encapsulate object creation and, since it’s abstract, it delegates the creation to its subclasses.
That sounds like exactly what they need in their case:
abstract class ToysFactory {
public function produceToy($toyName) {
$toy = null;
$toy = $this->createToy($toyName);
$toy->prepare();
$toy->package();
$toy->label();
return $toy;
}
abstract public function createToy($toyName);
}
Now in the New York branch, all they need to do is to implement the createToy()
method in their the subclass:
class NyToysFactory extends ToysFactory {
public function createToy($toyName) {
$toy = null;
if ('car'==$toyName) {
$toy = new NyCar();
} else if ('helicopter'==$toyName) {
$toy = new NyHelicopter();
}
return $toy;
}
}
For the factory in California, they have to create another subclass, CaToyFactory
, to produce toys locally:
class CaToysFactory extends ToysFactory {
public function createToy($toyName) {
$toy = null;
if ('car'==$toyName) {
$toy = new CaCar();
} else if ('helicopter'==$toyName) {
$toy = new CaHelicopter();
}
return $toy;
}
}
In the code above, the function createToy()
in the ToysFactory
class is called a factory method. Factory Method pattern defines an interface(createToy) for creating an object. But it delegates the actual creation to subclasses(NyToysFactory and CaToyFactory). This way subclasses decide what object to create.
Abstract Factory
> Provides an interface for creating families of related or dependent > objects without specifying their concrete classes.
Business is booming 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 don’t want franchisees to cut costs and use low-quality components. Low-quality toys would definitely destroy Dragon’s brand reputation. So, the CEO wants to franchise the business, but they still want to have factories 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.
First, let’s 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’s 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 the 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 the 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 the 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, the concrete factory method ToysFactory
needs to be modified. This is where we add the location specific ComponentsFactory
. 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 tutorial, we’ve built a franchise framework, giving Dragon Inc. control and enough freedom for each franchise to do what they’re good at.
Wrap-up
We hope you’ve enjoyed our guide! What you’ve read above is actually a chapter from our book “Understanding Design Patterns via real-life stories”. If you want to learn more design patterns in a similarly easy way, check out our book here.
Author: Star Tutorial