2026-04-24
You've used the Builder pattern for complex objects with many optional parameters. The Factory pattern solves a different problem: when the type of object you need depends on runtime conditions, and you don't want calling code to know the construction details.
Consider a notification system. You need to send alerts via email, SMS, Slack, or push notifications depending on user preferences:
Without a factory (the mess):
function sendAlert(user, message) {
if (user.prefersEmail) {
const smtp = new SmtpClient(config.smtp);
const email = new EmailNotification(smtp, user.email);
email.send(message);
} else if (user.prefersSlack) {
const token = vault.getSecret('slack-token');
const slack = new SlackNotification(token, user.slackId);
slack.send(message);
} else if (user.prefersSms) {
const twilio = new TwilioClient(config.sid, config.authToken);
const sms = new SmsNotification(twilio, user.phone);
sms.send(message);
}
}
Every place that sends notifications now carries the burden of knowing how to construct every notification type. Add a new channel? Hunt down every call site.
With a factory:
class NotificationFactory {
create(user) {
switch (user.preferredChannel) {
case 'email': return new EmailNotification(this.smtp, user.email);
case 'slack': return new SlackNotification(this.slackToken, user.slackId);
case 'sms': return new SmsNotification(this.twilio, user.phone);
default: return new EmailNotification(this.smtp, user.email);
}
}
}
// Calling code becomes trivial
function sendAlert(user, message) {
const notification = notificationFactory.create(user);
notification.send(message);
}
The calling code doesn't know or care which concrete type it gets. It just calls send(). This works because all notification types share a common interface.
When to use a factory vs. direct construction:
new Thing() in a factory just for the sake of it.Rule of thumb: If you see the same if/else or switch block selecting a type in 3+ places, extract a factory. Even in 1 place, a factory pays off once you hit 4+ branches — it keeps the selection logic testable in isolation and stops it from tangling with business logic.
Factories also make testing dramatically easier. Need to test sendAlert? Inject a factory that returns a mock notification. No SMTP server, no Twilio credentials, no Slack tokens in your test suite.
