Recommended Free Tools
In Kotlin, a factory is any creation API that hides or centralizes how an object is built. It can be a top-level function, a companion-object function, or an injectable factory abstraction; it does not have to be a class hierarchy. Choose the lightest form that makes construction clearer or more controllable.
What the factory pattern does in Kotlin
A factory separates a caller’s request for a product from the details of constructing the concrete object. That boundary is useful when creation involves validation, normalization, selecting an implementation, caching, or a policy that may change. If construction is already obvious and direct, a constructor is often simpler.
A companion-object factory can make creation a controlled entry point:
class User private constructor(val name: String) {
companion object {
fun create(name: String): User {
require(name.isNotBlank())
return User(name.trim())
}
}
}
val user = User.create("Ada")
Here the private constructor prevents callers from bypassing the factory. The validation and trimming are application choices in this example, not special behavior supplied by Kotlin.
#1 Best Overall
Common factory forms
Top-level function for simple creation
Use a top-level function when creation is straightforward and does not need to be attached to a type or injected as a dependency:
fun parseEndpoint(text: String): Endpoint = Endpoint.parse(text)
This keeps the call concise while giving the operation a descriptive name.
Rank #2
Companion-object function for type-qualified creation
Use a companion object when callers should write expressions such as Money.fromDollars(...) or User.create(...). Kotlin describes companion-object members as instance members of the companion object, not Java-style static members, even though they can be called through the containing class name (Kotlin documentation).
class Money private constructor(val cents: Long, val currency: String) {
companion object {
fun fromDollars(amount: BigDecimal, currency: String): Money =
Money(amount.movePointRight(2).longValueExact(), currency)
}
}
Use a name that tells the caller what is special about the creation, such as fromDollars, fromString, of, or createDefault. Kotlin’s coding conventions advise against giving a factory function the same name as its class when the factory has distinct semantics (Kotlin coding conventions).
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Rank #3
Factory interface when the creator is a dependency
Introduce a factory interface or class when the creator itself must be selected by configuration, replaced in tests, or shared as a collaborator by multiple clients:
interface ParserFactory {
fun create(format: Format): Parser
}
class DefaultParserFactory : ParserFactory {
override fun create(format: Format): Parser = when (format) {
Format.JSON -> JsonParser()
Format.XML -> XmlParser()
}
}
Clients can depend on ParserFactory and the Parser product contract rather than selecting concrete parsers themselves. Keep dependencies explicit: a global factory that can locate arbitrary services risks becoming a service locator rather than a focused creator.
Abstract Factory for a compatible product family
Use Abstract Factory when one creator supplies a coordinated set of related products that must work together—for example, a renderer and the matching widget theme. The client uses product interfaces and does not name the concrete implementations. If there is only one product decision, a function or small factory is easier to understand.
Factory Method, Abstract Factory, and a simple factory
| Approach | What it creates | When it fits |
|---|---|---|
| Simple or companion factory | Usually one product through a named creation function | Centralize one decision, conversion, or construction policy without adding a hierarchy. |
| Factory Method | One product type | A concrete creator decides which implementation of that product to instantiate. |
| Abstract Factory | A family of related products | Keep several products compatible while allowing the family implementation to vary. |
The key distinction is scope: Factory Method abstracts creation of one product type; Abstract Factory abstracts creation of a compatible family. Kotlin examples of both patterns are available in the design-pattern repository.
Best Value
Using sealed types when the variants are closed
A sealed class or interface is a good fit when a factory’s possible inputs or products are intentionally limited to a known set. Kotlin can then check whether a when expression covers every known case. Direct subclasses of a sealed type are known at compile time within Kotlin’s permitted module and package boundaries (Kotlin sealed classes documentation).
sealed interface PaymentMethod {
data class Card(val token: String) : PaymentMethod
data class BankTransfer(val iban: String) : PaymentMethod
data object Cash : PaymentMethod
}
fun paymentProcessor(method: PaymentMethod): Processor = when (method) {
is PaymentMethod.Card -> CardProcessor(method.token)
is PaymentMethod.BankTransfer -> BankProcessor(method.iban)
PaymentMethod.Cash -> CashProcessor()
}
This approach is less suitable when third parties must add implementations outside the module: a sealed hierarchy deliberately constrains the set of direct variants.
Choose the simplest form that meets the need
- Use a constructor when the concrete type and initialization are already clear and there is no meaningful creation policy to hide.
- Use a top-level function for a small, self-contained creation operation that has no need for a type-level home.
- Use a companion-object function when type-qualified syntax improves discoverability or construction should be controlled by the class.
- Use an injected factory when runtime configuration, environment, or test setup must choose or replace the creator.
- Use Abstract Factory only when clients need a coordinated family of compatible products.
- Use sealed variants when the set of supported cases is intentionally closed and exhaustive handling matters.
Before adding a factory, check whether overloaded constructors could instead use default arguments. Kotlin conventions recommend factory functions when constructor overloads cannot be reduced to a constructor with defaults, and favor names that explain the conversion or policy (Kotlin coding conventions). A factory can also provide a home for caching or test fakes when those are genuinely useful (Effective Kotlin).
Quick Recap
Trade-offs to watch
- A factory can centralize validation, subtype selection, caching, and future implementation changes while letting callers depend on a product interface.
- An unnecessary factory adds indirection to a trivial constructor and makes object creation harder to trace.
- A single factory with a long conditional for unrelated product types can become a difficult-to-maintain “god factory.” Split it by responsibility or let each variation own its creation decision.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.

