자바의 Static Factory Method

포모·2020년 12월 17일
0

Clean Code

목록 보기
6/6
post-custom-banner

자바 정적 팩토리 메소드는 객체를 생성하는 메소드를 만들고 static으로 선언하는, 객체 생성을 캡슐화하는 기법입니다.

  • 예시 : valueOf 메소드
BigInteger example = BigInteger.valudOf(42L);

이펙티브 자바 2판 "규칙1"
생성자 대신 정적 팩터리 메서드를 사용할 수 없는 지 생각해보라

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

  • valueOf, of : 여러개의 매개변수를 받아 객체 생성
  • getInstance, instance : 인스턴스를 생성. 이전에 반환했던 것과 같을 수 있습니다.
  • newInstance, create : 매번 새로운 인스턴스를 생성
  • from : 하나의 매개 변수를 받아 객체를 생성
  • getXxx : getInstance와 같으나 호출하는 클래스와 다른 타입의 인스턴스를 반환할 때 사용
  • newXxx : getXxxx와 같으나 매번 새로운 인스턴스를 반환한다.

장점

  • 이름이 있으므로 생성자에 비해 가독성이 좋다.
  • 호출할 때마다 새로운 객체를 생성할 필요가 없다.
  • 하위 자료형 객체를 반환할 수 있다.
  • 형인자 자료형 객체를 만들 때 편하다.

단점

  • 정적 팩토리 메서드만 있는 클래스라면, 생성자가 없으므로 하위 클래스를 만들 수 없다.
  • 다른 정적 메소드와 잘 구분되지 않는다.

특징

가독성이 좋다.

class Character {
	public Character(String Q, String W, String E, String R) {
		this.Q = Q;
		this.W = W;
		this.E = E;
		this.R = R;
	}
    
    // 정적 패턴 메소드 1
	public static Character Ashe() {
		return new Character("궁사의 집중", "일제 사격", "매날리기", "마법의 수정화살");
	}
	
    // 정적 패턴 메소드 2
    public static Character Teemo() {
		return new Character("실명 다트", "신속한 이동", "맹독 다트", "유독성 함정");    
    }

리그 오브 레전드 게임의 캐릭터를 담은 Character를 생성자를 사용해 객체를 생성해보자.

Character ashe = new Character("궁사의 집중", "일제 사격", "매날리기", "마법의 수정화살");

겜덕인 나는 보면 스킬이구나 하지만, 스킬 이름인지 모르는 사람은 저게 패시브인지, 아이템인지 헷갈릴 것이다.

Character ashe = Character.Ashe();

반면, 정적 패턴 메소드는 딱 봐도 애쉬 객체를 생성했다는 의미가 명확하다. 👍


호출할 때마다 새로운 객체를 생성할 필요가 없다

immutable 객체를 캐시해서 쓰고 있다면 굳이 new와 같은 비싼 연산을 해줄 필요가 없다.

private static final BigInteger ZERO = new BigInteger(new int[0], 0);

public static BigInteger valueOf(long val) {
	if (val == 0) {
		return ZERO;
	
	...
	}

위와 같이 0 같은 값을 호출할 때 일일이 생성하는 일을 피할 수 있습니다.


하위 자료형 객체를 반환할 수 있다.

class OrderUtil {

    public static Discount createDiscountItem(String discountCode) throws Exception {
        if(!isValidCode(discountCode)) {
            throw new Exception("잘못된 할인 코드");
        }
        // 쿠폰 코드인가? 포인트 코드인가?
        if(isUsableCoupon(discountCode)) {
            return new Coupon(1000);
        } else if(isUsablePoint(discountCode)) {
            return new Point(500);
        }
        throw new Exception("이미 사용한 코드");
    }
}

class Coupon extends Discount { }
class Point extends Discount { }

위 코드는 할인 코드에 따라 CouponPoint 객체를 리턴합니다.
이를 위해서 두 하위 클래스가 같은 인터페이스를 구현하거나, 같은 부모 클래스를 갖도록 하면됩니다.


🛴 마무리

valueOf가 가지는 이점을 잘 활용해서 코드에 적용하면 정말 유용할 거 같다는 생각이 들어 이렇게 정리해보게 되었습니다.
잘 사용하면 정말 가독성이 높아질 듯 하네요!


참고

post-custom-banner

0개의 댓글