스터디/이펙티브 자바

[Effective Java] Item 1. 생성자 대신 정적 팩토리 메서드를 고려하라

📝 작성 : 2022.05.11  ⏱ 수정 : 
728x90

정적 펙토리 메서드(static factory method)란?

정적 펙토리 메서드에서 펙토리란 객체를 생성하는 역할을 이야기 합니다. 즉 객체를 생성하는 static method라고 생각하면 편합니다.

정적 팩토리 메서드의 장점(생성자와 비교하여)

  1. 이름을 갖는다.
public class User {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public static User nameOf(String name) {
        return new User(name);
    }

    public static void main(String[] args) {
        User user1 = new User("홍길동");
        User user2 = User.nameOf("홍길동");
    }
}

단순히 new User("홍길동")으로 객체를 생성하는 것 보다 User.nameOf("홍길동")으로 홍길동이란 이름의 User를 생성한다는 것을 보다 명확하게 표현할 수 있습니다.

 

 

  1. 호출할 때마다 새로운 객체를 생성할 필요가 없다.
public class State {
    private static Map<String, State> stateNames = new HashMap<>();

    static {
        stateNames.put("서울", new State("서울"));
        stateNames.put("인천", new State("인천"));
        stateNames.put("대전", new State("대전"));
        stateNames.put("대구", new State("대구"));
        stateNames.put("부산", new State("부산"));
        stateNames.put("광주", new State("광주"));
    }

    private String stateName;

    private State(String stateName) {
        this.stateName = stateName;
    }

    public static State from(String stateName) {
        State state = stateNames.get(stateName);
        if (state == null) {
            throw new IllegalArgumentException("거기가 어딘가요?");
        }
        return state;
    }

    @Override
    public String toString() {
        return "여기는 " + stateName + "입니다.";
    }

    public static void main(String[] args) {
        State seoul = State.from("서울");
        System.out.println(seoul);

        State invalidState = State.from("충청남도");
    }
}

 

 

  1. 하위 자료형 객체를 반환한다.
public class Soap {
    public static Soap createSoap(int price) {
        if (price < 10000) return new IndustrialSoap();
        return new HandmadeSoap();
    }

    public static void main(String[] args) {
        Soap soap = Soap.createSoap(1000);
        System.out.println("soap instanceof Soap           Is " + (soap instanceof Soap));
        System.out.println("soap instanceof HandmadeSoap   IS " + (soap instanceof HandmadeSoap));
        System.out.println("soap instanceof IndustrialSoap IS " + (soap instanceof IndustrialSoap));
    }
}
class HandmadeSoap extends Soap{}
class IndustrialSoap extends Soap{}

 

 

  1. 입력 매개변수에 따라 다른 클래스의 객체를 반환할 수 있다.

List.of()메서드 입니다. 매개변수가 2개까지는 List12 3개 이상부터는 ListN을 반환하지만 사용하는 입장에서는 무엇을 반환하던 상관하지 않고 사용합니다. 또한 장점 3번의 예제도 가격에 따라 핸드메이드비누 또는 공산품비누를 리턴하므로 장점4번을 설명해주고 있습니다.

 

 

  1. 객체 생성을 캡슐화
@Getter
public class User {
    private Long id;
    private String name;
    private int age;
}

public class UserDto {
    private String name;
    private int age;

    public UserDto(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static UserDto from(User user) {
        return new UserDto(user.getName(), user.getAge());
    }
}

UserDto userDto1 = new UserDto(user.getName(), user.getAge());
UserDto userDto2 = UserDto.from(user);

이렇듯 정적 팩토리 메서드는 가독성을 향상시켜주고 좀 더 객체지향적으로 프로그래밍 할 수 있도록 도와줍니다.

 

정적 펙토리 메서드의 단점

  1. 상속을 하려면 public이나 protected 생성자가 필요하므로 정적 펙토리 메서드만 있는 경우 하위 클래스를 만들 수 없다.
  2. 정적 펙토리 메서드는 찾기가 어렵다. => 네이밍 컨벤션을 통해 확인

생성자를 쉽게 찾을 수 있습니다.
생성자 탭이 없고 Static Methods 탭에서 확인해야합니다.

 

정적 펙토리 메서드 네이밍 컨벤션

  • from: 하나의 매개변수를 받아서 같은 타입의 인스턴스를 반환(형변환)
  • of: 여러개의 매개변수를 받아서 적합한 타입의 인스턴스를 반환(집계)
  • valueOf: fromof의 자세한 버전
  • getInstance 또는 instance: 인스턴스를 반환, 같은 인스턴스임을 보장하지 않음
  • newInstance 또는 create: 인스턴스를 반환, 새로운 인스턴스임을 보장
  • getType: getInstance와 같으나, 다른 클래스의 인스턴스를 반환 "Type"은 반환할 객체의 타입
  • newType: newInstance와 같으나, 다른 클래스의 인스턴스를 반환 "Type"은 반환할 객체의 타입
  • type: getTypenewType의 간결한 버전
반응형