Explore how factory ideas appear in Scala through companions, smart constructors, family-oriented factories, and explicit creation boundaries.
Factory in Scala: A boundary that encapsulates how a value or service is created, often through companions, smart constructors, or small capability interfaces rather than heavy OO hierarchies.
Factory patterns still matter in Scala because creation decisions often need a home:
What changes is that many Scala factories become smaller and more direct than their classic textbook counterparts.
The simplest factory in Scala is often just a companion method:
1final case class Port private (value: Int)
2
3object Port {
4 def from(n: Int): Either[String, Port] =
5 if 0 <= n && n <= 65535 then Right(Port(n))
6 else Left("port out of range")
7}
This factory does real work:
newThat is enough for many application-level needs.
A lot of classic simple factory examples become unnecessary once construction lives naturally in a companion. A dedicated factory class becomes useful when:
If none of that is true, a companion often communicates the creation boundary more cleanly.
When one subsystem must create multiple related implementations together, the problem is still real:
Scala can express that with a trait returning the related capabilities:
1trait PersistenceFactory {
2 def users: UserRepository
3 def orders: OrderRepository
4}
That may be all the abstraction you need. You do not necessarily need a large “factory method plus product hierarchy” apparatus unless the design genuinely warrants it.
Construction can involve more than allocation:
If that work is effectful, the factory should be honest about it. Returning an effect or result type is usually clearer than disguising setup behind a pure-looking constructor.
If the only goal is calling new with one obvious argument, the extra abstraction may be empty ceremony.
A factory that performs I/O or environment lookup without signaling it clearly can mislead callers.
Some abstract factory structures are kept alive mostly out of loyalty to the pattern catalog, not because the system really needs them.
Start with companions and smart constructors. Move to capability-style or family-oriented factories only when runtime selection, richer assembly, or coordinated product families make them worthwhile. In Scala, a factory should make creation boundaries clearer, not merely more formal.