Introduce Polymorphic Creation With Factory Method

Destination
Symptom

A method conditionally constructs a collaborator based on a type code carried by the caller. The conditional grows wider with every new variant; each variant's construction details leak into the shared method body; the method changes for two unrelated reasons (algorithm and variant-set).

Goal

The base class declares an abstract Factory Method and uses the result polymorphically. Each subclass owns the creation knowledge for its variant; the base class's algorithm is conditional-free and stable.

Before the refactoring

// Branching on a type code to decide which collaborator to construct.
class DocumentReader {
constructor(format) {
this.format = format;
}
read(text) {
let parser;
if (this.format === 'xml') {
parser = new XmlParser();
} else if (this.format === 'json') {
parser = new JsonParser();
} else if (this.format === 'csv') {
parser = new CsvParser();
} else {
throw new Error(`unsupported format ${this.format}`);
}
return parser.parse(text);
}
}

After the refactoring

// Each subclass owns its createParser primitive; the base class is conditional-free.
class DocumentReader {
read(text) {
return this.createParser().parse(text);
}
createParser() {
throw new Error('abstract: subclasses must implement createParser');
}
}
class XmlReader extends DocumentReader {
createParser() {
return new XmlParser();
}
}
class JsonReader extends DocumentReader {
createParser() {
return new JsonParser();
}
}
class CsvReader extends DocumentReader {
createParser() {
return new CsvParser();
}
}
Example source: Illustrative example written for this site, adapted from Kerievsky's pattern description in Refactoring to Patterns (Addison-Wesley, 2004), chapter 6. The book frames this as the polymorphic alternative to type-code-driven construction; this JavaScript version uses document readers and parsers, same Factory Method shape.
Pressure

Type-code-driven construction is Shotgun Surgery waiting to happen — a new variant requires editing every conditional that branches on the type. The variant-set becomes a cross-cutting concern duplicated everywhere a related decision is made.

Tradeoff

Factory Method requires a class hierarchy; what was one class becomes a base plus subclasses. For variant sets that are stable and small (two or three formats that have never changed), a conditional may be cheaper than the inheritance ceremony.

Relief

The base class's algorithm is finalized; new variants land as new subclasses with no edits to the base. Per-variant creation is locally readable and locally testable; the algorithm's correctness is verified once.

Trap

A Factory Method whose only job is `return new X()` per subclass is constructor syntax with extra steps. The pattern pays when creation involves real choices — caching, parameter shaping, conditional sub-collaborators — not when it is a one-line `new`.