본문 바로가기
source-code/software

추상 팩토리(Abstract Factory) 패턴

by mattew4483 2023. 11. 8.
728x90
반응형

추상 팩토리 패턴이란?

추상 팩토리는 객체의 인스턴스 생성에 관여하며, 클래스 정의와 객체 생성 방식을 구조화/캡슐화하는 생성 패턴의 한 종류이다.

 

서로 연관되거나 의존적인 객체의 집합을 생성하기 위한 인터페이스를 제공해 구체적 클래스에 의존하지 않음으로써,

새로운 객체 생성 로직의 추가나 변경 사항에 쉽게 대응할 수 있다.

 

사용 예제

다음과 같은 요구 사항이 있었다.

1. DB에 Template이라는 table이 존재한다. (사용자가 입력한 여러 데이터로 구성)
2. 각 Template은 type이라는 속성을 갖는다. 해당 속성을 통해 Template의 종류를 구분한다. ex) modal, tool-tip...
3. 각 Template은 type에 따라 각기 다른 형태의 HTMLElement를 갖는다

 

연관된 객체(Template의 type에 맞는 요소)들이

각기 다른 생성 로직(modal과 tool-tip은 구현 자체가 다르다)을 가져야 하는 상황.

→ 추상 팩토리를 적용하기 최적의 상황!

 

export interface TemplateFactory {
  create(type:string, contents:string): TemplateFactoryProduct;
}

export interface TemplateFactoryProduct {
  getElement(): HTMLElement;
}

 

TemplateFactory라는 추상 팩토리의 인터페이스를 정의했다.

해당 인터페이스는 create라는 메서드를 통해 TemplateFactoryProduct 타입의 객체를 생성한다.

→ 해당 객체가 어떻게 생성되는지는 사용처에서 알 필요가 없어진다!

 

class ModalFactory implements TemplateFactory {
	create(content:string):TemplateFactoryProduct {
    	// ... modal 관련 구현 로직
    }
}

class TooltipFactory implements TemplateFactory {
	create(content:string):TemplateFactoryProduct {
    	// ... tooltip 관련 구현 로직
    }
}

 

각 template의 type에 맞는 Factory들을 생성한 모습!

 

class Application {
	templateFactory:TemplateFactory
	
    
    someMethod() {
    	const templateProduct = this.templateFactory().create()
        // 해당 templateFactory가 어떻게 구현되었는지는 신경쓰지 않음
    }
}

templateFactory를 사용하는 곳에서는,

해당 생성 로직과 상관없이 오직 TemplateFactory interface에만 의존할 수 있을 테다.

 

특이 사항

그런데... 여러 Factory들이 확장됨에 따라, interface 작성 시 이런  고민이 들었다.

현재 예시에서는 template의 종류인 modal과 tooltip이 content라는 속성을 통해 구성할 수 있는데...

만약 type에 따라 객체의 생성 시 필요한 요소들이 계속해서 달라진다면?

예를 들어... modal 생성을 위해 title, descriptioin이, tool-tip 생성을 위해 path가 필요하다면?

export interface TemplateFactory {
  create(type:string, contents:string, title:string, description:string, path:string) 
  // 메서드 인자가 무한정 늘어나야하나..?? 
  : TemplateFactoryProduct;
}

동료 서버 개발자분과 이런 얘기를 했는데 (마침 비슷한 고민을 한 적이 있으셨다)

결론은... 해당 도메인 interface를 사용해야 한다는 것!

 

즉 위 예시의 title, description, path, content 등은 모두 Template이라는 DB table 정의를 따를 테므로...

interface TemplateDto {
    content:string;
    title : string;
    type: string;
    description:string;
    path:string;
}


export interface TemplateFactory {
  create(template:TemplateDto): TemplateFactoryProduct;
}

위와 같이 TemplateDto에 의존하는 것이 확장 및 유지보수에 가장 적합하다고 생각되었다!

 

물론 이 경우 TemplateDto의 변경 사항에 지나치게 의존한다 볼 수도 있지만...

사실 해당 도메인을 정의한 DTO interface가 변경된다는 뜻은 → 이와 연관된 구현 로직은 당연히 몽땅 변경되어야 할 테다.

 

즉...

1. 추상 팩토리는 세부 속성보다 각 도메인 interface에 의존하는 방향이 낫고

2. 이를 반대로 말하자면 각 도메인 집합에 해당하는 객체를 기준으로, 추상 팩토리를 구성하는 것이 무엇보다 중요하겠다!

728x90
반응형