← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Factory Pattern

general Intermediate
debt(d7/e5/b5/t5)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints note automated=no and the code_pattern is 'new SomeComplexClass(...) scattered across codebase' — PHPStan (the only listed tool) can flag type issues but won't identify missing factory abstractions or factories returning concrete types instead of interfaces. Recognising misuse requires deliberate code review to spot scattered construction or coupling to concrete classes.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix says 'extract object creation logic into a factory' — this is not a one-line swap. Common mistakes like factories returning concrete types instead of interfaces, or scattered new X / new Y calls across the codebase, require identifying all call sites, introducing an interface, creating a factory class, and updating callers. This spans multiple files but is typically contained within one component rather than being a full cross-cutting architectural rework.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). The applies_to covers web, cli, and queue-worker contexts, meaning the factory abstraction (or its absence) affects all work streams. A well-applied factory reduces burden; but common mistakes like god-object factories with dozens of create methods, or factories coupled to concrete types, impose an ongoing tax on every future maintainer who must understand and navigate the factory layer. The pattern itself has moderate reach.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap (a documented gotcha most devs eventually learn)' (t5). The misconception field explicitly states that Factory Method and Abstract Factory are commonly conflated — developers assume they are 'just variations' when they solve fundamentally different scoping problems. Additionally, common mistakes show developers often return concrete types instead of interfaces, defeating the pattern's purpose. These are documented gotchas that most developers learn through experience, not catastrophic but meaningfully deceptive.

About DEBT scoring →

Also Known As

factory method abstract factory static factory

TL;DR

Delegates object creation to a dedicated factory, decoupling the creator from the created class and allowing subclass instantiation.

Explanation

Factory patterns (Factory Method, Abstract Factory, Static Factory) abstract object creation logic from consuming code. Instead of new ConcreteClass(), call a factory that decides which concrete class to instantiate based on parameters or configuration. This follows Dependency Inversion (depend on the interface returned, not the concrete class), makes construction logic testable, and makes swapping implementations easy. In PHP, static factory methods on value objects (Money::fromFloat(9.99, 'GBP')) are a lightweight pattern that centralises validation and construction.

Common Misconception

Factory Method and Abstract Factory are just variations of the same pattern. Factory Method defines an interface for creating one object, letting subclasses decide the class. Abstract Factory creates families of related objects. They solve different scoping problems — single object vs coordinated object families.

Why It Matters

The Factory pattern centralises object creation — callers don't need to know which concrete class to instantiate, making it easy to change implementations or add new ones without touching call sites.

Common Mistakes

  • Factories that return concrete types instead of interfaces — callers are still coupled to the implementation.
  • Static factory methods that cannot be overridden in subclasses — use instance factories for flexibility.
  • Over-using factories for simple objects that could just use new — factories are for creation that involves logic.
  • Factory classes with dozens of create methods — a sign the factory has grown into a god object.

Avoid When

  • You only ever create one type of object and the creation logic is trivial — a factory adds indirection with no benefit.
  • The factory itself becomes a god object that knows about every concrete class — defeats the purpose of abstraction.
  • Simple value objects with no dependencies — new Point(1, 2) is clearer than PointFactory::create(1, 2).

When To Use

  • The concrete class to instantiate is determined at runtime based on configuration or input.
  • Object creation involves complex setup, dependency resolution, or conditional branching.
  • You want to enforce that objects are always created in a valid state with required dependencies.
  • Testing — factories make it easy to swap real implementations for test doubles.

Code Examples

✗ Vulnerable
// Object creation scattered across codebase — hard to change:
$mailer = new SmtpMailer('smtp.example.com', 587, 'user', 'pass');
// Same constructor call in 12 places — change SMTP provider = 12 edits

// Factory — centralised:
class MailerFactory {
    public function create(): MailerInterface {
        return new SmtpMailer(config('mail.host'), config('mail.port'));
    }
}
✓ Fixed
interface Logger {
    public function log(string $msg): void;
}

class LoggerFactory {
    public static function create(string $driver): Logger {
        return match($driver) {
            'file'     => new FileLogger(),
            'database' => new DatabaseLogger(),
            'null'     => new NullLogger(),
            default    => throw new \InvalidArgumentException("Unknown driver: $driver"),
        };
    }
}

$logger = LoggerFactory::create($_ENV['LOG_DRIVER'] ?? 'file');

Added 15 Mar 2026
Edited 25 Mar 2026
Views 33
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 2 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 1 ping F 1 ping S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S
No pings yet today
No pings yesterday
Amazonbot 9 Perplexity 4 Ahrefs 2 Unknown AI 2 SEMrush 2 Majestic 1
crawler 20
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Low
⚡ Quick Fix
Extract object creation logic into a factory when construction is complex, involves conditions, or needs to be mocked in tests — factories keep the calling code clean of instantiation detail
📦 Applies To
any web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
new SomeComplexClass(new Dep1(), new Dep2(), $config->get('key')) scattered across codebase; conditional new X / new Y based on type flag
Auto-detectable: ✗ No phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: Class Tests: Update

✓ schema.org compliant