Factories
Factories enable efficient and simple production of (usually) complex objects. Let's use them to simplify our implementation interfaces.
TL;DR
The Factory pattern is a classic creational pattern. Some important reasons to use the pattern include that it appropriately encapsulates creation logic, as well as provides a structured way of creating objects in a deterministic manner.
Factories encapsulate the creation of, primarily, complex objects such as those in the domain layer. The pattern itself has nothing to do with DDD (instead, please see Design Patterns: Elements of Reusable Object-Oriented Software). In the context of DDD, we gain even better enforcement of encapsulation, which is especially meaningful when we need to construct an Entity or Aggregate.
Factories help us to hide implementation and construction logic and always return valid invariants of the class ("product") that we have created. However, invariant logic and validation should as far as possible be deferred to the product being created itself, which makes perfect sense if we are using Factories to create complex objects like Entities and Aggregates that already have such logic baked in.
You can probably imagine a case where the setup of an Aggregate will require pulling lots of parameters, checking validity, and other such stuffโthis is a perfect case of hiding that with a Factory. I've used Factories several times when I need to create an object that requires complicated asynchronous setups. By using the Factories we can avoid leaking out any of that complexity onto the user.
The way Factories are used in the example is very basic. There is nothing blocking you from applying the Factory pattern to creational methods on Aggregates or Services themselves (see for example Vernon 2013, p.391/397).
Examples of the pattern
To be fair, there are no good uses of "proper" and complex factories in Get-A-Room.
Often you will find factories in an object-oriented class shape, but here we will use a more TypeScript-idiomatic way of using functions.
Several factories have been used to remove some of the ugly new SomeClass()
calls. I'll happily use it whenever I want to avoid letting a user directly access a class, like this:
This also works well in creating concrete instances of services that need some values for setting them up:
More on the VerificationCodeService
later.
We can also use it to package some important checks or validations we may have, like with the EventBridge emitter:
While very basic, all of these (especially the two last ones) get the point across; A Factory can hide some of the ugly details involved in creating important objects.
For an excellent and more in-depth article on factories, see https://www.culttt.com/2014/12/24/factories-domain-driven-design or https://refactoring.guru/design-patterns/factory-method/typescript/example.
Overall, I highly recommend checking out the creational patterns at https://refactoring.guru/design-patterns/creational-patterns.
Last updated