개발자 공부 업무 정보/JAVA

생성자 대신 정적 팩터리 메서드를 고려하라

회님 2022. 12. 15. 13:32
반응형

클라이언트에서 인스턴스를 얻는 전통적인 수단은 public 생성자를 만드는 것입니다.
하지만 모든 프로그래머가 꼭 알아둬야 할 기법이 하나 더 있다.
바로 정적 팩토리 메서드이다.


정적 팩터리 메서드가 생성자보다 좋은 장점을 먼저 알아보자

 

  • 이름을 가질 수 있다.
    public StaticFactoryMethodA(String name) {
        this.name = name;

    }

    //vs

    public static StaticFactoryMethodA CreateStaticFactoryMethod(String name) {
        StaticFactoryMethodA staticFactoryMethodA = new StaticFactoryMethodA();
        staticFactoryMethodA.name = name;
        return staticFactoryMethodA;
    }
    // 이름을 가질 수 있기에 어떤 일을 하는지 정확하게 파악 할 수 있다.

생성자 자체는 반환될 객체의 특성을 제대로 설명하지 못한다.

반면 정적 팩토리는 이름만 잘 지으면 반환될 객체의 특성을 쉽게 묘사할 수 있다.

 

  • 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다.
    // second .  호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다.
    private static final StaticFactoryMethodA STATIC_FACTORY_METHOD = new StaticFactoryMethodA();

    private StaticFactoryMethodA(){}

    public static StaticFactoryMethodA getNewInstance() {
        return STATIC_FACTORY_METHOD;
    }

    // Test Code 참조
    @Test
    void getNewInstance() {
        StaticFactoryMethodA staticFactoryMethodA = StaticFactoryMethodA.getNewInstance();
        StaticFactoryMethodA staticFactoryMethodA2 = StaticFactoryMethodA.getNewInstance();
        System.out.println("(staticFactoryMethod == staticFactoryMethod2) = " + (staticFactoryMethodA == staticFactoryMethodA2));
        //(staticFactoryMethod == staticFactoryMethod2) = true
    }

생성자는  private로 제한하고 정적 팩토리 메서드로 인스턴스를 반환해주면 싱글턴을 유지할 수 있을뿐만 아니라 메서드 내에서 인스턴스 자체를 통제 할 수있다.

 

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

이 능력은 반환할 객체의 클래스를 자유롭게 선택할 수 있게 하는 '엄청난 유연성'을 선물한다.

아래 

출처 : https://k3068.tistory.com/52

static class CARD{
    public static final String SAMSUNG_CARD = "삼성";
    public static final String KAKAO_CARD="카카오";

    static Payment payment(String card){
        switch (card){
            case SAMSUNG_CARD:
                // 3. 반환 타입의 하위타입 객체를 반환할 수 있는 능력이 있다.
                return new SamSungPayment();
            case KAKAO_CARD:
                return new KakaoPayment();
        }
        throw new IllegalArgumentException();
    }

}

Payment라는 상위 타입 Interface로 하위 타입인 SamSungPayment 클래스를 숨김으로써

프로그래머는 *인터페이스대로 동작할 객체를 얻을 것을 알기에 * 굳이 SamSungPayment.class를 찾아가서 알아보지 않아도 된다.

 

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

세번째와 유사한 내용이며 유연하게 대응 가능하다는 점이다.

 

public abstract class StaticFactoryMethodB {
    // fourth . 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환 할 수 있다.
    abstract void getName();

    public static StaticFactoryMethodB getNewInstance(String code) {
        StaticFactoryMethodB staticFactoryMethodB = null;
        if (code.indexOf("2") == 1) {
            staticFactoryMethodB = new Point();
        } else {
            staticFactoryMethodB = new Coupon();
        }

        return staticFactoryMethodB;
    }


}

class Coupon extends StaticFactoryMethodB {
    public void getName() {
        System.out.println("쿠폰을 발행합니다");
    }
}

class Point extends StaticFactoryMethodB {
    public void getName() {
        System.out.println("포인트를 1000점 적립합니다");
    }
}

위와 같이 받는 code 값에 따라 매번 다른 클래스의 객체를 반환할 수 있다.

 

  • 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.
public abstract class StaticFactoryMethodC {
    // fifth . 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.

    public abstract void getName();

    public static StaticFactoryMethodC getNewInstance() {
        StaticFactoryMethodC staticFactoryMethodC = null;

        try {
            Class<?> aClass = Class.forName("prac.effectivejava.chapter2.item1.staticfactorymethod.StaticFactoryMethodChild");
            staticFactoryMethodC = (StaticFactoryMethodC) aClass.getDeclaredConstructor().newInstance();
        } catch (ClassNotFoundException e) {
            System.out.println("클래스가 없습니다");
        } catch (InstantiationException e) {
            System.out.println("메모리에 올릴 수 없습니다.");
        } catch (IllegalAccessException e) {
            System.out.println("클래스파일 접근 오류입니다.");
        } catch (InvocationTargetException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

        return staticFactoryMethodC;

        //Test 참조
    }

}
public class StaticFactoryMethodChild extends StaticFactoryMethodC {

    @Override
    public void getName() {
        System.out.println("정상 로드 되었습니다.");
    }
}

TEST CODE

class StaticFactoryMethodChildTest {

    @Test
    void getName() {
        StaticFactoryMethodC staticFactoryMethodC = StaticFactoryMethodC.getNewInstance();

        staticFactoryMethodC.getName();
        //정상 로드 되었습니다.
    }
}

 


post-thumbnail
이미지 클릭 시 책 구매 링크로 이동합니다.


 

"이 포스팅은 위 책을 참고하여 작성되었습니다."

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

 

 


 

 

 

GitHub - Kimjunghwoi/effectiveJava: 이펙티브 자바를 읽고 정리합니다.

이펙티브 자바를 읽고 정리합니다. Contribute to Kimjunghwoi/effectiveJava development by creating an account on GitHub.

github.com

 

반응형