Loading content...
Factory Method and Abstract Factory are the two most commonly confused design patterns. Both involve factories. Both abstract object creation. Both enable polymorphic product creation. Yet they solve fundamentally different problems and have different structural designs.
This confusion isn't surprising—the patterns are related. In fact, Abstract Factory often uses Factory Method internally. But understanding their distinction is crucial for correct pattern selection.
The One-Sentence Distinction:
Factory Method is about creating one product through inheritance. Abstract Factory is about creating families of products through object composition.
By the end of this page, you will understand the fundamental differences between Factory Method and Abstract Factory, know when to use each pattern, recognize the relationship between them, and be able to select the appropriate pattern for your specific design problem.
Let's start with the fundamental question each pattern answers:
| Pattern | Fundamental Question |
|---|---|
| Factory Method | "How do I let subclasses decide which single object to create?" |
| Abstract Factory | "How do I create families of related objects without specifying concrete classes?" |
This distinction cascades into different structures, participants, and use cases:
| Aspect | Factory Method | Abstract Factory |
|---|---|---|
| Primary Mechanism | Inheritance (subclass overrides method) | Composition (inject factory object) |
| Number of Products | Creates ONE product type | Creates FAMILIES of related products |
| Where Creation Happens | In a method that subclasses override | In a factory object composed into client |
| Creator Type | Abstract class with factory method | Interface/class with multiple factory methods |
| Product Relationship | Products are independent | Products must work together (family consistency) |
| Extension Model | Subclass the creator | Implement new factory class |
| Coupling Style | Subclass coupled to one product | Factory coupled to product family |
Factory Method uses inheritance: you create a subclass and override the factory method. Abstract Factory uses composition: you inject a factory object that creates products. This aligns with the classic "favor composition over inheritance" guidance—Abstract Factory is often more flexible for this reason.
Before comparing, let's ensure we understand Factory Method clearly. In Factory Method, a creator class declares an abstract method that returns a product. Subclasses provide the concrete implementation.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
/** * FACTORY METHOD PATTERN EXAMPLE * * Key characteristics: * 1. Creator (Document) is an ABSTRACT CLASS * 2. Factory method (createApplication) is ABSTRACT or DEFAULT * 3. Subclasses OVERRIDE the factory method * 4. Creates ONE product type per factory method */ // Product interfacepublic interface Application { void open(); void save(); void close();} // Concrete productspublic class WordProcessor implements Application { ... }public class SpreadsheetApp implements Application { ... }public class PresentationApp implements Application { ... } // CREATOR: Abstract class with factory methodpublic abstract class Document { private Application app; /** * The FACTORY METHOD. * Subclasses MUST override this to specify which app to create. */ protected abstract Application createApplication(); /** * Template method using the factory method. * Notice: The document doesn't know which app it will get. */ public void open() { if (app == null) { app = createApplication(); // Calls the factory method } app.open(); } public void save() { app.save(); }} // CONCRETE CREATORS: Subclasses that override factory methodpublic class TextDocument extends Document { @Override protected Application createApplication() { return new WordProcessor(); // TextDocument creates WordProcessor }} public class ExcelDocument extends Document { @Override protected Application createApplication() { return new SpreadsheetApp(); // ExcelDocument creates SpreadsheetApp }} public class PowerPointDocument extends Document { @Override protected Application createApplication() { return new PresentationApp(); // PowerPointDocument creates PresentationApp }} // UsageDocument doc = new TextDocument();doc.open(); // Internally creates WordProcessorFactory Method Key Points:
Document) is an abstract classcreateApplication()) is abstract and returns ONE product typeIn Abstract Factory, a factory interface declares methods for creating multiple related products. Concrete factories implement this interface for specific product families.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
/** * ABSTRACT FACTORY PATTERN EXAMPLE * * Key characteristics: * 1. Factory (GUIFactory) is an INTERFACE * 2. Multiple creation methods for RELATED products * 3. Concrete factories IMPLEMENT the interface * 4. Creates FAMILIES of products that work together */ // Product interfacespublic interface Button { ... }public interface TextField { ... }public interface Checkbox { ... } // Concrete products - Windows familypublic class WindowsButton implements Button { ... }public class WindowsTextField implements TextField { ... }public class WindowsCheckbox implements Checkbox { ... } // Concrete products - macOS familypublic class MacOSButton implements Button { ... }public class MacOSTextField implements TextField { ... }public class MacOSCheckbox implements Checkbox { ... } // ABSTRACT FACTORY: Interface with multiple creation methodspublic interface GUIFactory { Button createButton(); // Multiple products TextField createTextField(); Checkbox createCheckbox();} // CONCRETE FACTORIES: Implement interface for each familypublic class WindowsFactory implements GUIFactory { @Override public Button createButton() { return new WindowsButton(); } @Override public TextField createTextField() { return new WindowsTextField(); } @Override public Checkbox createCheckbox() { return new WindowsCheckbox(); }} public class MacOSFactory implements GUIFactory { @Override public Button createButton() { return new MacOSButton(); } @Override public TextField createTextField() { return new MacOSTextField(); } @Override public Checkbox createCheckbox() { return new MacOSCheckbox(); }} // CLIENT: Uses factory through interfacepublic class Application { private final GUIFactory factory; // Composed, not inherited public Application(GUIFactory factory) { this.factory = factory; // Injected from outside } public void buildUI() { Button btn = factory.createButton(); TextField field = factory.createTextField(); // All products are from the same family - guaranteed! }} // UsageGUIFactory factory = new WindowsFactory(); // Family selectionApplication app = new Application(factory); // Inject factoryapp.buildUI();Abstract Factory Key Points:
GUIFactory) is an interface (or abstract class)Let's visualize the structural differences side by side. Pay attention to the relationship arrows—they reveal the fundamental architectural difference.
Factory Method Structure:
The choice between Factory Method and Abstract Factory depends on your specific design problem. Here's a decision framework:
Ask yourself: "Do the products need to work together as a coherent set?" If yes, Abstract Factory. If each product is independent and used in isolation, Factory Method may suffice.
Let's examine the same domain through both pattern lenses to see how the choice affects design.
Scenario: A logging framework that can write to different destinations.
Factory Method Approach:
// Creator with factory method
public abstract class Logger {
protected abstract LogWriter createWriter();
public void log(String message) {
LogWriter writer = createWriter();
writer.write(format(message));
}
}
// Concrete creators
public class FileLogger extends Logger {
@Override
protected LogWriter createWriter() {
return new FileLogWriter("/var/log/app.log");
}
}
public class ConsoleLogger extends Logger {
@Override
protected LogWriter createWriter() {
return new ConsoleLogWriter();
}
}
✅ Good fit: Each logger type creates one writer. Products are independent. Subclassing is natural.
Abstract Factory Approach:
// Would require:
public interface LoggingFactory {
LogWriter createWriter();
// What else? Only one product!
}
❌ Poor fit: There's only one product type (LogWriter). No family coherence needed. Abstract Factory adds unnecessary complexity.
Verdict: Factory Method wins for single-product scenarios.
A key insight: Abstract Factory often uses Factory Method internally. Each creation method in an Abstract Factory is essentially a Factory Method. This is not contradiction—it's composition.
Consider this implementation detail:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
/** * Abstract Factory using Factory Methods internally. * * Each createX() method IS a factory method. * The Abstract Factory pattern composes multiple factory methods * into a coherent family-creation interface. */public interface GUIFactory { // Each of these is a Factory Method! Button createButton(); // Factory Method for buttons TextField createTextField(); // Factory Method for text fields Checkbox createCheckbox(); // Factory Method for checkboxes} /** * Concrete factory implements factory methods. */public class WindowsFactory implements GUIFactory { @Override public Button createButton() { // This IS a factory method implementation return new WindowsButton(); } @Override public TextField createTextField() { // Factory method for text fields return new WindowsTextField(); } @Override public Checkbox createCheckbox() { // Factory method for checkboxes return new WindowsCheckbox(); }} /** * Alternative: Abstract class with template method + factory methods. * This shows explicit Factory Method usage within Abstract Factory. */public abstract class ConfigurableGUIFactory implements GUIFactory { protected final Theme theme; public ConfigurableGUIFactory(Theme theme) { this.theme = theme; } @Override public Button createButton() { // Template method: create and configure Button button = doCreateButton(); // Factory method (abstract) configureComponent(button); return button; } @Override public TextField createTextField() { TextField field = doCreateTextField(); // Factory method (abstract) configureComponent(field); return field; } // Factory methods - subclasses override these protected abstract Button doCreateButton(); protected abstract TextField doCreateTextField(); // Shared configuration (template method pattern) private void configureComponent(Component component) { component.applyTheme(theme); }} public class WindowsFactory extends ConfigurableGUIFactory { public WindowsFactory(Theme theme) { super(theme); } @Override protected Button doCreateButton() { return new WindowsButton(); // Factory method implementation } @Override protected TextField doCreateTextField() { return new WindowsTextField(); // Factory method implementation }}Don't think of patterns as mutually exclusive. Abstract Factory is often composed of Factory Methods. Template Method often invokes Factory Methods. Patterns combine like building blocks.
Systems often evolve. A design that starts with Factory Method may grow to need Abstract Factory. Understanding this evolution path helps you make appropriate initial choices and refactor when needed.
new Button() directly in client code. Simple, works for single implementation.ButtonFactory with factory method. Subclasses determine which button.TextFieldFactory. Two parallel hierarchies emerging.GUIFactory with multiple creation methods. One factory for each family.Warning Signs You Need to Evolve:
| Current State | Warning Sign | Evolution Target |
|---|---|---|
| Direct instantiation | Need to vary what's created | Factory Method |
| Single Factory Method | Need multiple related products | Multiple Factory Methods |
| Multiple Factory Methods | Need family consistency | Abstract Factory |
| Abstract Factory | Families don't need consistency | Simplify to Factory Methods |
Resist Premature Abstraction:
Don't start with Abstract Factory when Factory Method (or even direct instantiation) suffices. Patterns add structural complexity. That complexity should be justified by actual requirements, not speculative flexibility.
If you only have one product type and foreseeable requirements, Factory Method or even simple instantiation is appropriate. Don't use Abstract Factory "just in case" you need families later. Refactoring from Factory Method to Abstract Factory is straightforward when needed.
Use this decision flowchart to select between Factory Method and Abstract Factory:
We've thoroughly compared Factory Method and Abstract Factory. Let's consolidate the key distinctions:
| Criterion | Factory Method | Abstract Factory |
|---|---|---|
| Products | One type | Family of types |
| Mechanism | Inheritance | Composition |
| Creator | Abstract class with method | Interface with methods |
| Extension | Create subclass | Implement interface |
| Consistency | Not enforced | Enforced by factory |
| Flexibility | Compile-time | Runtime (injection) |
| Complexity | Lower | Higher |
| Best For | Single product variation | Product family variation |
Congratulations! You've mastered the Abstract Factory pattern. You understand the problem it solves (creating families of related objects), the solution structure (factory interfaces with multiple creation methods), the participants (AbstractFactory, ConcreteFactory, AbstractProduct, ConcreteProduct, Client), and when to choose it over Factory Method. Apply this knowledge to build extensible, maintainable systems that handle product variation elegantly.