1. 팩토리 패턴(Factory Pattern)
- 객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴.
- 상속 관계에 있는 두 클래스에서 상위 클래스(부모 클래스)가 중요한 뼈대 결정.
- 하위 클래스(자식 클래스)에서 객체 생성에 관한 구체적인 내용 결정.
2. JavaScript의 팩토리 패턴
class CoffeeFactory {
static createCoffee(type) {
const factory = factoryList[type];
return factory.createCoffee();
}
}
class Latte {
constructor() {
this.name = 'latte';
}
}
class Espresso {
constructor() {
this.name = 'Espresso';
}
}
class LatteFactory extends CoffeeFactory {
static createCoffee() {
return new Latte();
}
}
class EspressoFactory extends CoffeeFactory {
static createCoffee() {
return new Espresso();
}
}
const factoryList = { LatteFactory, EspressoFactory };
const main = () => {
const coffee = CoffeeFactory.createCoffee('LatteFactory');
console.log(coffee.name);
};
main();
코드 분석
CoffeFactory(부모 팩토리 클래스)createCoffee(type)메서드를 통해 특정 커피 객체를 생성.type에 따라factoryList에서 적절한 서브팩토리 클래스(LatteFactory,EspressoFactory)를 찾아 커피 객체를 생성.
Latte,Espresso(커피 이름 클래스)- 각각
Latte와Espresso객체를 생성. this.name으로 커피의 종류를 저장.
- 각각
LatteFactory,EspressoFactory(자식 팩토리 클래스)CoffeFactory(부모 클래스)를 상속 받는 하위 팩토리 클래스.createCoffee()메서드를 오버라이딩해서 각각Latte또는Espresso객체를 반환.
factoryList(팩토리 클래스 매핑)- 팩토리 클래스를 관리하는 객체
- 키(key)는 문자열(
'LatteFactory','EspressoFactory') - 값(value)은 해당하는 팩토리 클래스.
CoffeFactory.createCoffee('LatteFactory')처럼 문자열을 사용하여 팩토리 클래스 선택 가능
main(실행 코드)CoffeeFactory.createCoffee('LatteFactory')를 호출하면 ~'LatteFactory'에 해당하는LatteFactory클래스를 찾음LatteFactory.createCoffee()호출 >new Latte()객체 생성coffee변수에Latte객체가 저장
실행 과정
main()함수 실행.CoffeeFactory.createCoffee('LatteFactory')호출.factoryList에서LatteFactory를 찾아서createCoffee()실행.LatteFactory.createCoffee()가new Latte()객체를 반환.coffee.name을 출력하면"latte"가 나옴.
Americano를 추가하는 방법(JavaScript)
class Americano {
constructor() {
this.name = 'Americano';
}
}
class AmericanoFactory extends CoffeeFactory {
static createCoffee() {
return new Americano();
}
}
factoryList['AmericanoFactory'] = AmericanoFactory;
새로운 커피 종류를 추가할 때 기존 코드 수정 없이 확장 가능 !!
3. Java의 팩토리 패턴
enum CoffeeType{
LATTE,
ESPRESSO
}
abstract class Coffee{
protected String name;
public String getName(){
return name;
}
}
class Latte extends Coffee{
public Latte(){
name = "latte";
}
}
class Espresso extends Coffee{
public Espresso(){
name = "Espresso";
}
}
class CoffeeFactory{
public static Coffee createCoffee(CoffeeType type){
switch (type){
case LATTE:
return new Latte();
case ESPRESSO:
return new Espresso();
}
}
}
public class Main{
public static void main(String[] args){
Coffee coffee = CoffeeFactory.createCoffee(CoffeeType.LATTE);
System.out.println(coffee.getName());
}
}
코드 분석
*enum: 상수의 집합을 정의할 때 사용되는 타입으로써 상수 뿐만 아니라 메서드를 집어 넣어 관리할 수 있음.
*enum CoffeeType(커피 타입 열거형)enum을 사용하여 커피의 종류를 미리 정의.CoffeeType.LATTTE,CoffeeType.ESPRESSO처럼 미리 정해진 값만 사용 가능 > 오타 방지, 가독성 향상.
abstract class Coffee(부모 클래스 == 추상 클래스)Coffee클래스는 추상 클래스(abstract class)로 선언됨.name필드를 가짐(각 커피 종류에서 이 값을 설정한다)getName()메서드를 통해 커피 이름을 가져올 수 있음.
Latte,Espresso(자식 클래스)Coffee클래스를 상속 받아서Latte,Espresso클래스를 만듬.- 생성자에서
name값을 설정해서 각 커피의 종류를 구분함.
CoffeeFactory(커피 생성 팩토리)createCoffee(CoffeeType type)메서드를 통해 입력된 타입에 맞는 커피 객체를 생성하여 반환.switch-case문을 사용하여CoffeeType.LATTE이면Latte객체 생성,CoffeeType.ESPRESSO이면Espresso객체 생성.
Main(실행 클래스)Coffee.Factory.createCoffee(CoffeeType.LATTE)를 호출하면 ~CoffeeFactory에서CoffeeType.LATTE를 받음.switch-case문에서LATTE에 맞는new Latte()객체를 생성해서 반환.coffee.getName()을 호출하면"latte"가 출력.
실행 과정
main()함수 실행.CoffeeFactory.createCoffee(CoffeeType.LATTE)호출.switch-case문에서LATTE에 해당하는new Latte()객체를 반환.coffee.getName()을 출력 >"latte"출력됨.
Americano를 추가하는 방법(Java)
class Americano extends Coffee {
public Americano() {
name = "americano";
}
}
// CoffeeFactory에 추가
class CoffeeFactory {
public static Coffee createCoffee(CoffeeType type) {
switch (type) {
case LATTE:
return new Latte();
case ESPRESSO:
return new Espresso();
case AMERICANO:
return new Americano(); // 새로운 커피 추가
default:
throw new IllegalArgumentException("Invalid coffee type:" + type);
}
}
}
4. 팩토리 패턴의 장단점
장점
- 객체 생성 로직을 캡슐화: 객체 생성 방식이 변경 되거나 추가 되어도 기존 코드를 수정할 필요가 없음 > 유지보수 쉬움, 가독성 향상
- 결합도 낮추기 > 유연한 코드 설계 가능: 클라이언트 코드가 특정 클래스에 의존하지 않음.
- 코드 재사용성 증가: 팩토리 클래스 하나만 유지보수하면 되기 때문에 보일러플레이트 코드 최소화
단점
*단일 책임 원칙(SRP): 하나의 클래스는 단 하나의 기능이나 변경 이유를 가져야 한다
- 코드 복잡성 증가: 클래스 수가 증가하고, 코드가 복잡해져서 작은 규모의 프로젝터에서는 오히려 불필요한 패턴임.
- *단일 책임 원칙(SRP) 위반 가능성: 팩토리 클래스 하나가 여러 객체 생성을 담당하게 되면, 단일 책임 원칙에 위배될 수 있음 > 팩토리 클래스는 역할별로 분리할 것 !
5. 팩토리 패턴을 적용하는 대표적인 경우
- 자동자 공장 시스템
- UI 컴포넌트 생성
- DB 연결
6. 결론
팩토리 패턴은 객체 생성 로직을 캡슐화하여 유지보수성과 확장성을 높이는 디자인 패턴이다.
객체 생성 로직을 캡슐화하여 유지보수가 쉬워진다 !
클라이언트 코드의 결합도를 낮춰 새로운 객체를 추가할 때 유연하게 확장할 수 있다 !
코드 복잡성이 증가할 수 있으므로, 프로젝트 규모와 필요성에 따라 신중하게 적용해야 한다 !
'Computer Science > Design Pattern' 카테고리의 다른 글
| 이터레이터 패턴(Iterator Pattern) (0) | 2025.03.21 |
|---|---|
| 프록시 패턴(Proxy Pattern) (0) | 2025.03.19 |
| 옵저버 패턴(Observer Pattern) (1) | 2025.03.19 |
| 전략 패턴(Strategy Pattern) (1) | 2025.03.18 |
| 싱글톤 패턴(Singleton Pattern) (1) | 2025.03.14 |
