Creational Abstractions: The Factory Patterns
Factories decouple the **usage** of an object from its **instantiation**. This is critical for maintaining the Open/Closed Principle: you can add new implementations without modifying the client code that consumes them.
I. The Static Factory Method
Often preferred over constructors, static factory methods provide named intent and can return cached instances or subtypes.
**Example: Named Intent**
```java
public class PaymentRequest {
public static PaymentRequest forCreditCard(double amount) { ... }
public static PaymentRequest forCrypto(double amount) { ... }
}
```
II. The Functional Factory (Modern Java)
In the lambda era, we can replace complex `switch` statements with a `Map` of `Suppliers`. This is the "Modern Factory" pattern.
Concrete Example: Dynamic Document Parser
```java
public class ParserFactory {
private static final Map<String, Supplier<Parser>> PARSERS = Map.of(
"JSON", JsonParser::new,
"XML", XmlParser::new,
"CSV", CsvParser::new
);
public static Parser getParser(String format) {
Supplier<Parser> constructor = PARSERS.get(format.toUpperCase());
if (constructor == null) throw new IllegalArgumentException("Unknown format");
return constructor.get(); // Lazy instantiation
}
}
```
III. Abstract Factory: Families of Objects
Use Abstract Factory when you need to ensure that a set of related objects are created together consistently.
**Example: Cloud Provider Abstraction**
```java
public interface CloudFactory {
ComputeInstance createCompute();
StorageBucket createBucket();
}
public class AwsFactory implements CloudFactory { ... }
public class AzureFactory implements CloudFactory { ... }
```
IV. Technical Considerations
1. **Reflection vs. New:** Traditional factories using `Class.forName().newInstance()` are slow and bypass compile-time checks. Prefer functional suppliers or **ServiceLoaders**.
2. **DI Integration:** In Spring/Guice, the container is the factory. Use `@Lookup` or `Provider<T>` when you need a new instance inside a singleton.
3. **Testability:** Avoid global static state in factories. Inject the factory interface into the client so you can mock the object creation in unit tests.
---
**See Also:**
- [Builder Pattern](BuilderPatternAndFluentApis) — For complex, multi-stage construction.
- [Repository Pattern](RepositoryPattern) — Often uses factories to reconstruct domain objects from persistence.
- [Design Patterns Hub](DesignPatternsHub) — Core architectural index.