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

mhyun, Park·2022년 3월 21일
0
post-thumbnail

Client가 클래스의 인스턴스를 얻는 전통적인 수단은 public 생성자이다.
하지만, 이외에도 클래스는 생성자와 별도로 정적 팩토리 메서드를 제공할 수 있다.

정적 팩토리 메소드
한 Class의 인스턴스를 반환하는 단순한 정적 메소드

ex) Boolean.java

public static Boolean valueOf(boolean b) {
	return b ? Boolean.TRUE : Boolean.FALSE
}

장점

(1) 이름을 가질 수 있다

  • 소수를 구하는 BigInteager 이용 시 둘중에 어느것이 더 전달력이 좋을까?
	BigInteager(int, int, Random)
	vs
	BigInteager.probalblePrime(int, Random)

(2) 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다

  • 인스턴스를 미리 만들어 놓거나 캐싱하여 재활용하는 식으로 불필요한 객체 생성을 피할 수 있다.

(3) 반환 타입의 하위 타입 객체를 반환할 수있는 능력이 있다.

  • 내부적으로 반환할 객체의 클래스를 자유롭게 선택할 수 있게 하는 '엄청난 유영성'을 선물한다.
  • 클래스를 공개하지 않고도 그 객체를 반환할 수 있어 API를 작게 유지할 수 있다.
public abstract class Fruit {
    
    abstract void getName();
    
    static public Fruit getNewInstance(String code) {
    
        switch(code) {
            case "apple": 
            	return new Apple()
            case "banana": 
            	return new Banana()
            default: /*some logic*/
        }
    }
}

class Apple extends Fruit {
    public void getName() {
        System.out.println("Apple");
    }
}

class Banana extends Fruit {
    public void getName() {
        System.out.println("Banana");
    }
}

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

  • Enumset()처럼 반환 타입의 하위 타입이기만 하면, 어떤 클래스의 객체를 반환하든 상관없다.
  • Client는 팩토리가 건네주는 객체가 어느 클래스의 인스턴스인지 알 수도 없고 알 필요도 없다.
public abstract class Fruit {
   
    protected int property;
    
    static public Fruit getNewInstance() {
    	if (property == 0) {
        	return new HotFruit();
        }
        
        return new ColdFruit();
    }
    
}

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

  • 메서드 안에서 객체를 반환할 때, 당장 클래스가 존재하지 않아도
    특정 Text파일에서 인터페이스 구현체의 위치를 알려주는 곳의 정보를 가지고 해당 객체를 읽어 생성할 수 있다.
public abstract class Fruit {
    
    public abstract void getName();
    
    public static Fruit getNewInstance() {
        try {
            Class<?> class = Class.forName("com.android.example.Fruit");
            return (Fruit) class.newInstance();
        } catch (Exception e) {
        	/* error */
        }
    }
}

단점

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

  • 해당 제약은 상속보다 컴포지션을 사용하도록 유도하고 불변 객체 생성을 위해선 오히려 장점으로 다가올 수 있다.

(2) 정적 팩토리 메서드는 프로그래머가 찾기 어렵다.

  • API 문서를 잘 써놓고 메서드 이름에 신경써야 한다.
  • 자주 사용하는 정적 팩토리 메서드 Naming
    • from
    • of
    • valueOf
    • instance / getInstance:
    • create / newInstance
    • getType
    • newType

Item 1 정리

큰 생각없이 public 생성자를 이용하여 객체를 생성하지 말고
정적 팩토리 메소드를 사용함으로써 얻는 이득을 알았으니 객체 쓰임에 따라 한번 더 고려하자.

profile
Android Framework Developer

0개의 댓글