객체 생성을 캡슐화하는 기법
좀 더 구체적으로 객체를 생성하는 메소드를 만들고, static으로 선언하는 기법
ex)
BigInteger answer = BigInteger.valueOf(50L); //BigInger 50을 리턴함
valueOf도 static으로 선언되어 있는 메서드이며, new BigInteger(...) 생성자를 은닉하고 있다는 사실을 알 수 있음
ex)
class Character {
int intelligence, strength, hitPoint, magicPoint;
public Character(int intelligence, int strength, int hitPoint, int magicPoint) {
this.intelligence = intelligence; // 지능
this.strength = strength; // 힘
this.hitPoint = hitPoint; // HP
this.magicPoint = magicPoint; // MP
}
클래스 내 AllArgsConstructor 생성자 선언
// 정적 팩토리 메소드
public static Character newWarrior() {
return new Character(5, 15, 20, 3); // 전사는 힘과 HP가 높다
}
// 정적 팩토리 메소드
public static Character newMage() {
return new Character(15, 5, 10, 15); // 마법사는 지능과 MP가 높다
}
}
만약 생성자를 사용해 전사나 마법사를 생성한다면
Character warrior = new Character(5, 15, 20, 3);
Character mage = new Character(15, 5, 10, 15);
코드만 봤을 때는 매개변수 숫자로 되어있기 때문에 캐릭터의 직업이 무엇인지 알아보기 어렵다.
하지만, 정적 팩토리 메서드를 사용한다면
Character warrior = Character.newWarrior();
Character mage = Character.newMage();
위에서와 같이 마법사와 전사를 만드는 코드는 정적 팩토리 메서드를 호출할 때마다 new Character(...)를 호출하게 됨
그러나 immutable 객체를 캐시해서 쓰고 있다면 굳이 일일이 new같은 무거운 연산을 사용할 필요가 없다.
ex)
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 객체를 선택적으로 리턴하고 있다.
이를 위해서는 두 하위 클래스가 같은 인터페이스를 구현하거나 ,같은 부모 클래스를 갖도록 하면 된다.