# The Factory Pattern Explained (with Java and Spring Examples)

## 1\. What is the Factory Pattern?

The Factory Pattern is a creational pattern that **delegates object creation** to a separate component (a “factory”) instead of using `new` directly. This helps you decouple object creation logic from the rest of your code.

### 🔤 Basic Example (using if-else)

```java
interface Shape {
    void draw();
}

class Circle implements Shape {
    public void draw() { System.out.println("Drawing Circle"); }
}

class Square implements Shape {
    public void draw() { System.out.println("Drawing Square"); }
}

class ShapeFactory {
    public Shape create(String type) {
        if ("circle".equals(type)) return new Circle();
        if ("square".equals(type)) return new Square();
        throw new IllegalArgumentException("Unknown type: " + type);
    }
}

// ✅ Using the factory
ShapeFactory factory = new ShapeFactory();
Shape shape = factory.create("circle");
shape.draw(); // Output: Drawing Circle
```

This simple example shows the key idea:

> Instead of calling `new Circle()` directly, the client asks the factory to create the object.

---

## 2\. Why Use It?

* To **hide complex instantiation logic**
    
* To **choose an implementation at runtime**
    
* To follow the **Open-Closed Principle** — adding new types without modifying client code
    

---

## 3\. Isn’t `if-else` a violation of Open-Closed?

Yes. A factory like this:

```java
if ("circle".equals(type)) return new Circle();
if ("square".equals(type)) return new Square();
```

…requires modifying code to add new types — a violation of the Open-Closed Principle.

✅ Instead, use a `Map<String, Supplier<Shape>>`:

```java
Map<String, Supplier<Shape>> registry = Map.of(
    "circle", Circle::new,
    "square", Square::new
);
```

Or an `enum` to encapsulate creation:

```java
public enum ShapeType {
    CIRCLE(() -> new Circle()),
    SQUARE(() -> new Square());

    private final Supplier<Shape> constructor;
    ShapeType(Supplier<Shape> c) { this.constructor = c; }
    public Shape create() { return constructor.get(); }
}
```

### ⚠️ Common Gotcha: `new Circle()` vs `Circle::new`

Don’t confuse storing a constructor with storing an instance.

```java
map.put("circle", new Circle());   // ❌ one shared object  
map.put("circle", Circle::new);    // ✅ a new object each time you call .get()
```

Using `Supplier<Shape>` lets you store a **constructor reference**, so the factory creates a new object every time — which is exactly what you want in most cases.

---

## 4\. Does Spring Replace the Factory Pattern?

**Most of the time, yes.**

Spring is a Dependency Injection container — it creates, wires, and manages object lifecycles for you. In many applications, this eliminates the need to write factories manually.

You can typically combine the idea of selecting a runtime implementation of a given interface while still delegating object creation to the Spring Framework.  
For example, consider the following setup:

### ✅ Registering multiple implementations in Spring

Suppose you have different implementations of an interface:

```java
public interface FileParser {
    void parse(String content);
}
```

You can register each one as a named Spring bean:

```java
@Component("json")
public class JsonParser implements FileParser { ... }

@Component("xml")
public class XmlParser implements FileParser { ... }
```

Now, Spring can inject all available `FileParser` beans into a map:

```java
@Component
public class ParserFactory {

    private final Map<String, FileParser> parsers;

    public ParserFactory(Map<String, FileParser> parsers) {
        this.parsers = parsers;
    }

    public FileParser getParser(String type) {
        FileParser parser = parsers.get(type.toLowerCase());
        if (parser == null) {
            throw new IllegalArgumentException("Unsupported file type: " + type);
        }
        return parser;
    }
}
```

### ✅ Usage example

```java
String fileType = request.getParam("type"); // User input
FileParser parser = parserFactory.getParser(fileType);
parser.parse(content);
```

This pattern lets you **keep all objects managed by Spring**, while still **choosing the right one at runtime**.

---

## 5\. Disadvantages of the Factory Pattern

Like all patterns, it comes with trade-offs:

* **Indirection**: More layers = more cognitive overhead for simple cases
    
* **Still needs registration**: Adding new types usually requires registering them somewhere (e.g., in a map or enum)
    
* **Harder debugging**: Errors during instantiation may be less obvious
    
* **Overuse**
    

## 6\. Conclusion

The Factory Pattern helps you **encapsulate logic to select the right implementation of an interface**. Use it when dealing with multiple implementations, dynamic decisions, or complex object creation.

It’s simple and effective, especially when combined with Dependency Injection frameworks like **Spring**.

Use it consciously to keep your design flexible, while being mindful of trade-offs like **added indirection** and **registration overhead**.
