자바 정적 팩토리 메소드는 객체를 생성하는 메소드를 만들고
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 { }
위 코드는 할인 코드에 따라 Coupon
과 Point
객체를 리턴합니다.
이를 위해서 두 하위 클래스가 같은 인터페이스를 구현하거나, 같은 부모 클래스를 갖도록 하면됩니다.
valueOf
가 가지는 이점을 잘 활용해서 코드에 적용하면 정말 유용할 거 같다는 생각이 들어 이렇게 정리해보게 되었습니다.
잘 사용하면 정말 가독성이 높아질 듯 하네요!