이번에 정리 할 내용은 팩토리 메소드 패턴이네요..
여기서 중요한 것도 역시 변화되는 부분을
따로 캡슐화 시킨다는 것입니다.
전 세계적으로 프랜차이즈를 하고 있는 햄버거집이 있습니다.
햄버거를 만드는데는 절차가 필요합니다.
재료를 준비하고 - 패티를 굽고 - 패티,빵,야채를 조합하고 - 포장을 합니다.
이 순서는 전세계 어디서나 똑같이 적용됩니다.
하지만 나라별로 그 나라 사람들의 기호에 따라서 햄버거의 재료에 조금씩 차이가 있습니다.
예를들어 중국은 돼지고기와 밀빵 케첩을 사용하고
한국은 한우와 쌀빵 머스터드소스를 사용합니다.
미국은 닭고기와 밀가루빵 마요네즈를 사용합니다.
(물론 실제로 저렇지는 않죠.. -_-)
하지만, 햄버거를 만드는 절차 자체는 모든 프랜차이즈점이 동일해야 합니다.
그러면, 햄버거 가게를 한번 만들어 보겠습니다.
public HamBurger orderHamburger(String type) {
HamBurger hamburger;
hamburger = createHamburger(type);
hamburger.prepare();
hamburger.roastPetty();
hamburger.mixStuff();
hamburger.box();
return hamburger;
}
abstract HamBurger createHamburger(String type);
}
햄버거를 만드는 절차는 동일하기 때문에, 추상클래스인 HamburgerStore에서 그 부분을
구현해 놓습니다. 일종의 프레임웍을 잡아 놓은 셈이죠. 하지만, 국가별로 햄버거의 스타일은
조금씩 다릅니다. 그 달라지는 부분을 캡슐화 시켜낸 것이 포인트입니다.
보시면 createHamburger(String type) 메소드가 추상 메소드로 선언되어 있습니다.
즉, 이 HamburgerStore를 상속해서 만들어지는 KoreaHamburgerStore나 ChinaHamburgerStore는
저 추상메서드 createHamburger(String type), 즉 국가별로 조금씩 스타일이
다른 햄버거를 리턴해주는 메소드를 구현해야 합니다.
바뀌는 부분은 너희들이 알아서 바꿔서, 나한테는 아무튼 Hamburger만 넘겨주면
잡혀있는 프레임웍에 맞춰서 햄버거를 만들게. 라는 것입니다.
그럼, 한국지점과 중국지점의 스토어를 만들어 보겠습니다.
public class KoreaHamburgerStore extends HamburgerStore {
@Override
public HamBurger createHamburger(String type) {
if("bigmac".equals(type)) return new KoreaBicmacBurger();
else if("double".equals(type)) return new KoreaDoubleBurger();
else return null;
}
}
-----------------------------------------------------------------
public class ChinaHamburgerStore extends HamburgerStore {
@Override
public HamBurger createHamburger(String type) {
if("bigmac".equals(type)) return new ChinaBicmacBurger();
else if("double".equals(type)) return new ChinaDoubleBurger();
else return null;
}
}
우리나라나 중국이나 빅맥이나 치킨버거 메뉴는 동일하게 존재하지만 위에서 언급했다시피
거기에 사용되는 재료는 조금씩 차이가 납니다.
그 부분을 감안해서 햄버거 클래스를 만들어 보겠습니다.
String name;
String meat;
String bread;
String source;
public void prepare() {
System.out.println("재료를 준비합니다..." + name);
}
public void roastPetty() {
System.out.println(meat + "를 구워냅니다.");
}
public void mixStuff() {
System.out.println(bread + "와 "+meat+"패티와 " + source + "를 사용해 햄버거를 만듭니다.");
}
public void box() {
System.out.println("포장을 합니다.");
}
}
재료에 대한 상태를 가질 수 있게 인스턴스 변수가 선언되어 있고
햄버거를 만드는 과정이 기본적으로는 구현되어 있습니다. 필요한 곳에서 이것을 오버라이드해서
사용해도 될겁니다. 상세 햄버거 클래스를 보겠습니다.
public class ChinaBicmacBurger extends Hamburger {
public ChinaBicmacBurger() {
name = "China BicMac Burger";
meat = "돼지고기";
bread = "밀빵";
source = "캐첩";
}
}
-----------------------------------------------------------
public class KoreaBicmacBurger extends Hamburger {
public KoreaBicmacBurger() {
name = "Korea BicMac Burger";
meat = "한우소고기";
bread = "쌀빵";
source = "머스터드";
}
}
국가별로 조금씩 다른 재료를 하위 클래스에서 직접 set 해주고 있습니다.
public static void main(String[] args) {
HamburgerStore store = new KoreaHamburgerStore();
HamburgerStore store2 = new ChinaHamburgerStore();
Hamburger burger = store.orderHamburger("bigmac");
Hamburger burger2 = store2.orderHamburger("bigmac");
}
}
한우소고기를 구워냅니다.
쌀빵와 한우소고기패티와 머스터드를 사용해 햄버거를 만듭니다.
포장을 합니다.
재료를 준비합니다...China BicMac Burger
돼지고기를 구워냅니다.
밀빵와 돼지고기패티와 캐첩를 사용해 햄버거를 만듭니다.
포장을 합니다.
햄버거를 만들기 위해서 store를 만들고 orderHamburger만 호출하면 됩니다.
그리고 HamburgerStore도 햄버거를 만드는데 있어서 실제로 그 햄버거의 구현 객체가 무엇인지
신경쓰지 않습니다. Hamburger 타입만 받으면 그것을 가지고 그냥 정해진 절차에 따라서
햄버거를 만들뿐입니다.
hamburger = createHamburger(type);
"나는 니가 한국빅맥버거인지 중국빅맥버거인지 신경쓰지 않아. 하지만 Hamburger가 리턴될 거라는 것은 알고 있고, Hamburger라면 준비하고, 고기굽고, 재료를 믹스하고 포장을 할 수 있다는 것도 알지."
.
지금 이것이 팩토리메소드 패턴입니다.
여기서 HamburgerStore가 생산자 클래스가 되고 그것을 상속한
KoreaHamburgerStore가 바로 구현 생산자 클래스가 됩니다.
그리고 Hamburger와 그것을 상속한 KoreaBigMacBurger가 바로 제품 클래스가 됩니다.
팩토리에서 제품을 생산하듯이 Store에서 Hamburger를 만들어 내죠.
구현 생산자 클래스인 KoreaHamburgerStore와 ChinaHamburgerStore에는 각각 나라의
햄버거에 대한 모든 사항이 캡슐화 되어 있습니다.
이 패턴이 앞에 작성한 심플 팩토리와 다른 가장 큰 차이점은
심플팩토리는 일회용으로 객체를 리턴시키는 반면에
이 팩토리 메소드 패턴은 어떤 구현체를 사용할지 서브클래스에서 결정하는 일종의
프레임워크를 만들 수 있다는 부분입니다. (HamburgerStore의 orderHamburger(String type) 메소드)