추상 팩토리 패턴 ( Abstract Factory Pattern )
추상 팩토리 패턴이라는 이름만 봐서는 팩토리 메서드 패턴과 비슷해보이지만, 명확한 차이점이 있습니다.
- 팩토리 메서드 패턴
- 조건에 따른 객체 생성을 팩토리 클래스로 위임하여, 팩토리 클래스에서 객체를 생성하는 패턴
- 추상 팩토리 패턴
- 서로 관련이 있는 객체들을 통째로 묶어서 팩토리 클래스로 만들고, 이들 팩토리를 조건에 따라 생성하도록 다시 팩토리를 만들어서 객체를 생성하는 패턴
- 추상 팩토리 패턴은 어떻게 보면, 팩토리 메서드 패턴을 좀 더 캡슐화한 방식이라고 볼 수 있습니다.
예)
- 컴퓨터를 생산하는 공장이있을때 마우스,키보드,모니터의 제조사로 samsung, lg 가 있다고 가정한다.
- 컴터를 생성할땐 구성품 전부 삼성으로 만들거나, 전부 lg 로 만들어야된다.
- 다시말하면 삼성컴퓨터 객체는 항상 삼성 마우스,키보드,모니터 객체들이 묶여서 생산되어야 합니다.
- 객체를 일관적으로 생산해야 할 필요가있다.
- 또한 코드 레벨에서 보면 삼성인지 lg 인지 조건에따라 분기될것이기때문에 팩토리 매서드 패턴과 같이, 조건에 따라 객체를 생성하는 부분을 factory 클래스로 정의할것입니다.
주의할 것은 추상 팩토리 패턴이 팩토리 메서드 패턴의 상위호환이 아니라는 것입니다.
두 패턴의 차이는 명확하기 때문에 상황에 따라 적절한 선택을 해야할 것입니다.
해당 언어는 ts 기반입니다
1. 추상 팩토리 패턴 사용 이유 - 팩토리 메서드 패턴을 사용할 경우의 문제
- 먼저 키보드 관련 클래스들을 정의하겠습니다.
- LGKeyboard와 SamsugKeyboard 클래스를 정의하고, 이를 캡슐화하는 Keyboard 인터페이스를 정의합니다.
- 그리고 KeyboardFactory 클래스에서 입력 값에 따라 LGKeyboard 객체를 생성할지, SamsungKeyboard를 생성할지 결정합니다.
- mouse 관련클래스도 keyboard와 동일합니다
class LGKeyboard implements Keyboard {
public keyboard_data(){
return console.log("LG 키보드 생성");
}
}
class SamsungKeyboard implements Keyboard {
public keyboard_data(){
return console.log("Samsung 키보드 생성");
}
}
interface Keyboard {
keyboard_data()
}
class KeyboardFactory {
public createKeyboard( type){
switch (type){
case "LG":
var keyboard = new LGKeyboard();
keyboard.keyboard_data()
break;
case "Samsung":
var keyboard = new SamsungKeyboard();
keyboard.keyboard_data()
break;
}
return null;
}
}
class LGMouse implements Mouse {
public mouse_data(){
console.log
("LG 마우스 생성");
}
}
class SamsungMouse implements Mouse {
public mouse_data(){
console.log
("Samsung 마우스 생성");
}
}
interface Mouse {
mouse_data()
}
class MouseFactory {
public createMouse(type){
switch (type){
case "LG":
var mouse = new LGMouse();
mouse.mouse_data()
break;
case "Samsung":
var mouse = new SamsungMouse();
mouse.mouse_data()
break;
}
return null;
}
}
- 다음으로 ComputerFactory 클래스를 구현합니다.
- ComputerFactory 클래스는 KeyboardFactory와 MouseFactory 객체를 생성해서 어떤 제조사의 키보드와 마우스를 생산할 것인지 결정합니다.
class ComputerFactory {
public createCompute(type){
let keyboardFactory = new KeyboardFactory();
let mouseFactory = new MouseFactory();
keyboardFactory.createKeyboard(type);
mouseFactory.createMouse(type);
console.log("--- " + type + " 컴퓨터 완성 ---");
}
}
- 마지막으로 구현이 잘되었는지 test 코드를 작성합니다.
- const test_2 = new ComputerFactory() test_2.createCompute("LG")
LG 키보드 생성
LG 마우스 생성
--- LG 컴퓨터 완성 ---
팩토리 메서드 패턴을 사용하여, 컴퓨터를 생산해보았습니다.
그런데 컴퓨터의 구성품은 키보드, 마우스 뿐만 아니라 본체 구성품들, 모니터, 스피커, 프린터 등등 여러가지가 있죠.
위의 코드를 그대로 사용하고자 한다면, 본체팩토리, 모니터팩토리, 스피커팩토리, 프린터팩토리 클래스를 정의해야 하고,
CoumputerFactory에서는 예를 들어, 다음과 같이 각 팩토리 클래스 객체들을 생성해서 컴퓨터가 완성이 될 것입니다.
public class ComputerFactory {
public void createComputer(String type){
KeyboardFactory keyboardFactory = new KeyboardFactory();
MouseFactory mouseFactory = new MouseFactory();
BodyFactory bodyFactory = new BodyFactory();
MonitorFactory monitorFactory = new MonitorFactory();
SpeakerFactory speakerFactory = new SpeakerFactory();
PrinterFactory printerFactory = new PrinterFactory();
keyboardFactory.createKeyboard(type);
mouseFactory.createMouse(type);
bodyFactory.createBody(type);
monitorFactory.createMonitor(type);
speakerFactory.createSpeaker(type);
printerFactory.createPrinter(type);
System.out.println("--- " + type + " 컴퓨터 완성 ---");
}
}
- 그런데 사실 Samsung 컴퓨터라면 구성품이 모두 Samsung이어야 하고, LG 컴퓨터라면 구성품이 모두 LG인 것이 맞습니다.
- 즉, 각각의 컴퓨터 구성품들을 Samsung이냐 LG냐 구분할 필요가 없이,
- Samsung 컴퓨터를 만들고자 한다면 구성품이 모두 Samsung이 되도록, 일관된 방식으로 객체를 생성할 필요가 있습니다.
- 또한 구성품이 늘어날수록 팩토리 객체를 생성하는 부분이 더욱 길어지겠죠.
- 따라서 추상 팩토리 패턴을 적용하여 구성품이 모두 동일한 제조사가 되도록 개선해보겠습니다.
패턴 적용 전과 비교했을 때의 차이점은 다음과 같습니다.
- 어떤 제조사의 부품을 선택할지 결정하는 팩토리 클래스( KeyboardFactory, MouseFactory )가 제거되고, Computer Factory 클래스가 추가되었습니다. ( SamsungComputerFactory, LGComputerFactory )
- SamsungComputerFactory, LGComputerFactory는 ComputerFactory 인터페이스로 캡슐화하고, 어떤 제조사의 부품을 생성할 것인지 명확하므로, 각각의 제조사의 부품을 생성합니다. ( 일관된 객체 생성 )
- FactoryOfComputerFactory 클래스에서 컴퓨터를 생산하는 createComputer() 메서드를 호출합니다.
각 클래스는 자신의 제조사 부품 객체를 생성합니다.
예를 들어, SamsungComputerFactory 클래스는 삼성 키보드, 마우스를 가지므로 SamsungKeyboard, SamsungMouse 객체를 생성합니다.
class SamsungComputerFactory implements ComputerFactory {
public createKeyboard() {
return new SamsungKeyboard();
}
public createMouse() {
return new SamsungMouse();
}
}
class LGComputerFactory implements ComputerFactory {
public createKeyboard() {
return new LGKeyboard();
}
public createMouse() {
return new LGMouse();
}
}
interface ComputerFactory {
public createKeyboard();
public createMouse();
}
다음으로 FactoryOfComputerFactory 클래스를 정의합니다.
이 클래스는 패턴 적용 전 ComputerFactory 클래스와 하는일이 같습니다.
입력값에 따라 객체 생성을 분기하는데요, 이 때 어떤 제조사 컴퓨터 객체를 생성할지 결정합니다.
즉, 부품이 아니라 컴퓨터 객체를 생성한다는 점에서 차이점이 있습니다.
class FactoryOfComputerFactory {
public createComputer(type){
switch (type){
case "LG":
var computerFactory = new LGComputerFactory();
computerFactory.createKeyboard();
computerFactory.createMouse()
break;
case "Samsung":
var computerFactory_1 = new SamsungComputerFactory();
computerFactory_1.createKeyboard()
computerFactory_1.createMouse()
break;
}
return null;
}
}
- 마지막으로 구현이 잘되었는지 test 코드를 작성합니다.
const nana = new FactoryOfComputerFactory()
nana.createComputer("Samsung")
결과는 이전과 동일합니다.
feat -- https://victorydntmd.tistory.com/300?category=719467
'OOD > Creational Design Patterns(생성패턴)' 카테고리의 다른 글
Creational Pattern(생성 패턴) 개념 모음 (0) | 2021.11.23 |
---|---|
Singleton Pattern(싱글톤 패턴) (0) | 2021.11.22 |
Builder Pattern(빌더 패턴) (0) | 2021.11.22 |
Factory Method patterns (0) | 2021.11.22 |