Factory Method 에서 한 가지 문제가 있었습니다. Concrete Creator 의 종류가 많아지면 애플리케이션의 코드 수정이 불가피하다는 것이었습니다. 디자인 패턴을 사용하는 목적에는 요구사항의 수정등이 있을 경우 change 가 파급되는 영역을 최소화하는 것도 있습니다.
자 그럼 결론 부터 보지요. 아래 class diagram 을 봐주세요.
[caption id="" align="aligncenter" width="450" caption="Abstract Factory Pattern class diagram from Wikipedia (GPL licensed)"][/caption]
네 이게 Abstract Factory 입니다. Concrete Factory 들에 대해 부모 클래스를 하나 뒀지요. 부모 클래스는 Concrete Factory 들이 가지고 있어야할 인터페이스를 정의합니다.
Factory Method 패턴과 차이점이 뭘까요? Factory Method 에서 마지막에 나온 Application code 를 보면
[CODE]
// Application code
FruitStore store = GuyFruitStore();
Fruit f = store.TakeMoneyAndGive( MySelf );
[/CODE]
라고 되어있었죠. 만약 과일상점이 GuyFruitStore() 가 아니라 새로 생긴 아줌만 과일 상점이 생기게 되어 월화수 에는 총각 가게를 가고 목금토일은 아줌마 가게를 간다고 합시다. 그럼 코드가 이렇게 되겠지요.
[CODE]
// Application code
FruitStore store;
if ( today == Mon || today == Tue || today == Wed)
store = new GuyFruitStore();
else
store = new AzummaFruitStore();
Fruit f = store.TakeMoneyAndGive( MySelf );
[/CODE]
라고 수정이 됩니다. 게다가 새로운 가게가 생길 때마다 위의 if-else 문 의 종류가 코드 곳곳에서 점점 많아지게 되지요. 저런 분기문을 없애기 위해서 Abstract Factory 라는 상위 클래스를 정의하게 됩니다.
또, 총각 과일 가게에서 파는 사과와 아줌마 가게에서 파는 사과를 공통으로 다루기 위해서 각 Product 별로 상위 클래스를 역시 정의하게 되지요. 그림에서 AbstractProductA 와 AbstractProductB 가 그것입니다. 그럼 클라이언트 코드에서는 어떤 클래스들만 다루게 될까요?
[CODE]
AbstractFruitStore store = GetTodaysStore();
Fruite f = store.TakeMoneyAndGive( MySelf );
[/CODE]
네 이렇게 하면 GetTodaysStore() 라는 함수 안에서 어떤 과게에 가라고 지시가 나오는 대로 수행을 하면 되네요. 더 많은 과일가게 들이 생겨도 클라이언트 코드는 변경되지 않습니다. 다만 그때 그때 GetTodaysStore() 함수만 수정을 해주면 되지요.
Abstract Factory 의 장점은 총각 가게와 아줌마 가게가 쉽게 바뀐 것 처럼 Factory 간의 교체가 쉽다는 점입니다. 한편 단점이라고 한다면, 바로 AbstractProduct 클래스입니다. Factory 에서 생성해내는 종류별로 존재해야 되기 때문에 번거롭다는 단점이 있지요.