정적 팩토리 메서드란

기본 생성자가 아닌 static 메서드로 객체를 생성하고 리턴하는 패턴

public class Car {

    private String model;

    // 생성자
    public Car(String model) {
        this.model = model;
    }

    // 정적 팩토리 메서드
    public static Car from(String model) {
        return new Car(model);
    }
    
}

Why?

1. 생성자 로직이 이름을 가질 수 있다.

Character 객체를 생성할 때 초보자와 마법사에 따라 생성하는 로직을 명시할 수 있다. 단순히 new 로 명명할 때 보다 가독성이 높아진다. 또한, 코드에서 볼 수 있듯이 생성자 로직은 private 으로 감싸 캡슐화를 유지한다.

public class Character {

    ...
    
    // 생성자 감춘다.
    private Character(String name, int health, int mana) {
        ...
    }

    // "초보자" 생성
    public static Character createNovice(String name) {
        return new Character(name, 50, 10);
    }

    // "마법사" 생성
    public static Character createWizard(String name) {
        return new Character(name, 80, 150);
    }
}

2. 인스턴스 생성을 직접 관리/확장할 수 있다.

클래스에 대해 인스턴스를 생성하는데 완전한 주도권을 갖게된다. 그렇다면 미리 자주 쓰이며 불변인 객체를 만들어 두고 반환하면 될테다. 싱글톤과 캐싱의 개념이다.

미리 Settings에 대한 불변 객체를 만들어 두고 생성자는 막고 정적 팩토리 메서드를 열어둔다. 그럼 다른 곳에서는 미리 생성되어 있는 객체만 반환된다. 캐싱에서도 활용할 수 있다.

3. 하위 타입을 반환한다.

image.png

인터페이스를 하나 두고 아래에 N개의 클래스를 둬서 해당 인터페이스를 반환하는 정적 팩토리 클래스/메서드를 둘 수 있다.

// 인터페이스
interface Shape {
    void draw();
}

// 구현 클래스 1
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("원을 그립니다.");
    }
}

// 구현 클래스 2
class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("사각형을 그립니다.");
    }
}

// 팩토리 클래스
public class ShapeFactory {
    // 반환 타입은 인터페이스인 Shape 입니다.
    public static Shape createShape(String type) {
        if ("circle".equalsIgnoreCase(type)) {
            // 실제 반환되는 객체는 Circle 클래스의 인스턴스입니다.
            return new Circle();
        } else if ("square".equalsIgnoreCase(type)) {
            // 실제 반환되는 객체는 Square 클래스의 인스턴스입니다.
            return new Square();
        }
        throw new IllegalArgumentException("지원하지 않는 도형입니다.");
    }
}

명명 규칙

image.png