Every day design pattern: Factory
The previous two chapter of this blog series were about the decorator and the adapter. These are structural design patterns. Meaning they deal with the structure of a system. They can help with simplifying relationships, and moving responsibilities.
The factory is a completely different type of design pattern. Its a creational pattern. A creation pattern is intended to make creation of objects easier. I generally use one when a class needs a multiple parameters, but only a few need to be ‘dynamic’. Lets take a look at an example.
Lets say we have SaaS where multiple companies use our system. They all have their own accounts. So we have an account service, which takes an account repository, but also the id of the current company. When we create the account service, we need to know this id, but we don’t really care about the repository it uses.
interface AccountRepository
{
public function findByEmail(string $email, int $companyId): ?Account;
}
class AccountService
{
public function __construct(
private AccountRepository $repository,
private int $companyId
) {}
public function getAccountByEmail(string $email): Account
{
$account = $this->repository->findByEmail($email, $this->companyId);
if ($account === null) {
throw AccountNotFoundException::fromEmail($email);
}
return $account;
}
}
When we use a factory to create this service it would look like this. When creating the object we need to know the company id. It may be a query parameter, or we know it because of the url that is visited. Whatever the case, we only know this at runtime, and can’t do this beforehand in a configuration or something like that.
class AccountServiceFactory
{
public function __construct(
private AccountRepository $repository
) {}
public function create(int $companyId): AccountService
{
return new AccountService($this->repository, $companyId);
}
}
Another reason to create a factory, may be to simplify creation. This is especially useful
when you provide a package. Lets look at react-php. They provide a static factory class,
which is used to create a LoopInterface
. Which one you can use is depending on installed
extension, and php versions. The class is even called Factory
An excerpt of the class looks like this. When you need a LoopInterface, all you have to do
is Factory::create()
. It means you don’t have to worry about having the correct extensions
ready, just to get started.
final class Factory
{
public static function create()
{
if (function_exists('uv_loop_new')) {
return new ExtUvLoop();
} elseif (class_exists('libev\EventLoop', false)) {
// more elseifs
}
return new StreamSelectLoop();
}
}
When not to use a factory
Sometimes, i see factories being used when they don’t add any ease of use:
An example may be the following factory:
class UserFactory
{
public function newUser(
string $name,
string $email,
string $passwordHash
): User {
return new User(
$name,
$email,
$passwordHash
);
}
}
Here the factory doesn’t make instantiation of the user any easier, instead it just adds another step before the creation of the object.
In conclusion
The factory pattern is used to make creation of objects easier. Either by deciding which one to create, or by splitting up when certain parameters are required.