[이펙티브 자바] 생성자 대신 정적 팩터리 메서드를 고려하라 :: 잡다한 프로그래밍
반응형

- 정적 팩터리 메서드는 클래스에 정적 메서드를 정의하여, 생성자 대신 객체를 생성할 수 있게 만드는 기법이다.

 

장점 1. 이름을 가진 생성자

 

생성자는 기본적으로 이름을 가질수 없다.

아래와 같은 클래스가 존재한다고 했을때, 다른 개발자가 해당 생성자를 보고 코드를 직관적으로 이해할 수 있을까?

public class Test {
    private int no;
    private String name;

    public Test(int no) {
        this.no = no;
    }

    public Test(String name) {
        this.name = name;
    }
}
Test test1 = new Test(1);
Test test2 = new Test(2);

이렇게 코드를 작성하면, 다른 개발자가 생성자 인자에 no, name을 전달해야한다는 사실을 직관적으로 이해할 수 없다.

 

정적 팩터리 메서드를 사용한 객체 생성

public class Test {
    private int no;
    private String name;

    private Test(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public static Test createById(int id) {
        return new Test(id, null);
    }

    public static Test createByName(String name) {
        return new Test(0, name);
    }
}

생성자에 private 접근 제어자를 두어 new 키워드로 직접 객체를 생성할 수 없게 하고, 정적 메서드를 통해  Book 객체를 생성한 뒤 반환하게한다.

Test test1 = Test.createById(1);
Test test2 = Test.createByName("이름");

이로서 생성자는 이름을 가지게 되고, 좀 더 직관적으로 바뀌게 된다.

 

장점 2. 호출될때마다 인스턴스를 생성하지 않아도 된다.

public class Test {
    private int no;
    private String name;

    private Test(int no, String name) {
        this.no = no;
        this.name = name;
    }

    private static final Test TEST_INSTANCE = new Test(1, "test");

    public static Test getInstance() {
        return TEST_INSTANCE;
    }
}

 

장점 3. 호출될때마다 인스턴스를 생성하지 않아도 된다.

class Parent {
    public static Parent child1() {
        return new Child1();
    }

    public static Parent child2() {
        return new Child2();
    }

    public static Parent child3() {
        return new Child3();
    }
}

class Child1 extends Parent {
    // ...
}

class Child2 extends Parent {
    // ...
}

class Child3 extends Parent {
    // ...
}

 

장점 4. 인자에 따라 다른 클래스 객체 반환 가능 (장점3과 비슷함)

장점 5. 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.

- 서비스 제공자 프레임워크를 만드는 근간이 된다. (ex. JDBC)

  public static void main(String[] args) {
      ServiceLoader<HelloService> loader = ServiceLoader.load(HelloService.class);
			// 첫번째 구현체를 가져옴(있을수도 없을수도 optional로 가져옴
      Optional<HelloService> helloServiceOptional = loader.findFirst();

      helloServiceOptional.ifPresent(h -> {
         System.out.println(h.hello());
      });
   }

단점1. 상속을 하려면 public이나 protected 생성자가 필요하니, 정적 팩토리 메소드만 제공하면 하위 클래스를 만들 수 없다.

위의 예제처럼 생성자를 private로 생성하기 때문에 상속받을 수 없다는 단점이 있다.

반응형

+ Recent posts