추상팩토리 패턴에 대해서 팩토리메서드 패턴과 비교하여 살펴보자.
| 구분 | 팩토리 메서드 패턴 | 추상팩토리 패턴 |
| 중점 | 단일 객체의 생성 중점 | 관련된 객체 집합의 생성 중점 |
| 구성 | 주로 단일 추상 클래스에 있는 하나의 팩토리 메서드 를 사용하여 객체를 생성 |
여러 관련된 팩토리 메서드들을 가진 하나의 추상 팩토리가 존재 각 팩토리 메서드는 다른 종류의 객체를 생성 |
| 확장성 | 서브클래스가 팩토리 메서드를 오버라이딩하여 객체 생성을 변경가능 | 새로운 종류의 객체 집합을 생성하기 위해 새로운 추상 팩토리를 생성가능 |
단순하게 설명해보자면,
추상 팩토리패턴은 여러개의 팩토리 클래스가 존재한다.
그 팩토리 클래스들은 가장 최상단의 추상팩토리클래스를 상속받아 구현한다.
공통화된 인터페이스는 가장 최상단의 추상팩토리클래스에서 정의를 하고, 각각의 팩토리클래스에서 코드를 확장하면 된다.
팩토리메서드패턴은 하나의 팩토리클래스를 이용하지만, 추상팩토리패턴은 여러개의 팩토리클래스를 이용하게 되어 팩토리메서드 패턴보다 좀 더 추상화와 캡슐화를 하게 된다.
코드를 통해 살펴보자.
회사별로 셔츠를 만든다고 가정해보자.
// Shirts 클래스
class Shirts {
private tag: string;
constructor(_tag) {
this.tag = _tag;
}
setTag(_tag) {
this.tag = _tag;
}
getTag() {
return this.tag;
}
}
// 팩토리메소드 패턴
// Shirts 객체를 생성하는 팩토리를 구현
class 옷공장 {
typeMap: {
A회사: Shirts;
B회사: Shirts;
};
createShirts(_type) {
if (_type === "A회사") {
return new Shirts(_type);
} else if (_type === "B회사") {
return new Shirts(_type);
}
}
}
const factoryMethodMain = () => {
const data = [
{ type: "A회사", attrs: { price: 50000 } },
{ type: "B회사", attrs: { price: 400000 } },
];
const factory = new 옷공장();
const 회사리스트 = data.map((v) => factory.createShirts(v.type));
console.log("회사리스트", 회사리스트);
};
factoryMethodMain();
팩토리메소드 패턴은 회사가 추가될시 `createShirts` 메서드에 코드가 계속 추가 되어지게 된다.
새로운 종류의 회사가 추가될때마다 조건절을 추가해야하므로 코드의 확장성이 떨어질수 있다.
위의 팩토리메소드패턴을 추상클래스패턴으로 변경해본 코드이다.
// 추상팩토리 패턴
interface AbstractClothesFactory {
createShirts: () => Shirts;
}
class A회사Factory implements AbstractClothesFactory {
createShirts() {
return new Shirts("A회사");
}
}
class B회사Factory implements AbstractClothesFactory {
createShirts() {
return new Shirts("B회사");
}
}
const abstractFactoryMain = () => {
const createShirts = (factory: AbstractClothesFactory) => {
return factory.createShirts();
};
const a = createShirts(new A회사Factory());
const b = createShirts(new B회사Factory());
console.log(a);
console.log(b);
};
우선 구현에 필요한 것들을 나열해보자.
- Shirts 클래스
- createShirts를 추상화한 추상클래스
- 회사팩토리클래스
- 확장 될시에, C회사팩토리 ... Z회사팩토리를 만들면된다.
구현방식을 풀어보면 이렇다.
먼저 추상클래스(AbstractClothesFactory) 에서 구체화해야할 메서드를 추상화한다.
팩토리패턴에서는 하나의 팩토리클래스에서 `createShirts`메서드의 조건절을 수정하여 회사를 추가했었다.
추상팩토리패턴에서는 회사별로 팩토리클래스를 생성하고, 그 클래스에서 추상클래스를 상속받아 `createShirts` 메소드를 오버라이딩 한다.
이제 객체를 생성할 메인함수 에서는 `createShirts` 함수를 생성한다.
함수의 매개변수는 추상 팩토리 클래스를 선언하고 추상팩토리클래스의 `createShirts` 메서드를 실행하여 회사별 객체를 생성할 수 있다.
결과적으로 추상팩토리패턴으로 구현을 하게 될시의 이점은 이렇다.
회사가 추가될때마다, 조건문을 추가하여 회사객체를 생성하지 않아 `createShirts` 부분에서 코드추가가 불필요해진다.
회사가 추가될때마다, C회사Factory 클래스를 생성하고, 추상클래스(AbstractClothesFactory) 를 상속받고 구현하면된다.
즉 팩토리클래스와 추가되는 객체만 추가하면 된다.
예를들어, Shirts말고도 Jacket, Pants등 여러종류가 추가될수도 있을것이다.
class Jacket {
private tag: string;
constructor(_tag) {
this.tag = _tag;
}
setTag(_tag) {
this.tag = _tag;
}
getTag() {
return this.tag;
}
}
interface AbstractClothesFactory {
createShirts: () => Shirts;
createJacket: () => Jacket;
}
class A회사Factory implements AbstractClothesFactory {
createShirts() {
return new Shirts("A회사");
}
createJacket() {
return new Jacket("A회사");
}
}
class B회사Factory implements AbstractClothesFactory {
createShirts() {
return new Shirts("B회사");
}
createJacket() {
return new Jacket("B회사");
}
}
class C회사Factory implements AbstractClothesFactory {
createJacket() {
return new Jacket("C회사");
}
createShirts() {
return new Shirts("C회사");
}
}
const abstractFactoryMain = () => {
const createShirts = (factory: AbstractClothesFactory) => {
return factory.createShirts();
};
const data = [new A회사Factory(), new B회사Factory(), new C회사Factory()];
const 회사리스트 = data.map((v) => createShirts(v));
console.log(회사리스트);
/**
* [ Shirts { tag: 'A회사' }, Shirts { tag: 'B회사' }, Shirts { tag: 'C회사' } ]
*/
};
'디자인패턴GoF > 생성패턴' 카테고리의 다른 글
| 자바스크립트로 이해해보는 싱글톤패턴 (SingleTone Pattern) In 생성패턴 (0) | 2023.11.27 |
|---|---|
| 자바스크립트로 이해해보는 팩토리메소드패턴 (FactoryMethod Pattern) In 생성패턴 (0) | 2023.11.03 |
| 자바스크립트로 이해해보는 프로토타입패턴 (Prototype Pattern) In 생성패턴 (1) | 2023.10.29 |
| 자바스크립트로 이해해보는 빌더패턴 (Builder Pattern) In 생성패턴 (0) | 2023.10.27 |