디자인 패턴 - 팩토리 패턴

kyle·2023년 8월 8일
0

CS

목록 보기
1/3

안녕하세요, 이번 시간엔 디자인 패턴 중 하나인 팩토리 패턴에 대해 알아보는 시간을 갖도록 하겠습니다.

팩토리 패턴?

팩토리 패턴(Factory Pattern)은 객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴이자 상속 관계에 있는 두 클래스에서 상위 클래스가 중요한 뼈대를 결정하고, 하위 클래스에서 객체 생성에 관한 구체적인 내용을 결정하는 패턴입니다.

상위 클래스와 하위 클래스가 분리되기 때문에 느슨한 결합을 가집니다.
상위 클래스에서는 인스턴스 생성 방식에 대해 전혀 알 필요가 없기에 더 많은 유연성을 갖게 됩니다.

그리고 객체 생성 로직이 따로 떼어져 있기 때문에 코드를 리팩토링하더라도 한 곳만 고칠 수 있게 되니 유지보수성이 증가합니다.

예를 들어 아이폰 레시피와 안드로이드폰 레시피라는 구체적인 내용이 들어있는 하위 클래스가 컨베이어 벨트를 통해 전달되고, 상위 클래스인 휴대폰 공장에서 이 레시피들을 토대로 휴대폰을 생산하는 생산 공정을 생각하면 됩니다.

장점

  1. 상위 클래스와 하위 클래스는 느슨한 결합을 가짐.
  2. 상위 클래스에서는 인스턴스 생성 방식에 대해 전혀 알 필요가 없기에 더 많은 유연성을 가짐.
  3. 로직 분리로 유지보수성이 증가함.

단점

  1. 모듈들의 분리로 인한 클래스 개수 증가로 복잡성 증가를 야기함.
  2. 약간의 런타임 패널티 발생

자바스크립트에서 팩토리 패턴을 구현한다면 간단하게 new Object()로 구현할 수 있습니다.

const num = new Object(42);
const str = new Object('test');

console.log(num.constructor.name); //Number;
console.log(str.constructor.name); //String;

위 코드에서 보실 수 있듯, new Object()에 인자로 넘긴 데이터에 따라 다른 타입의 객체를 생성하는 것을 확인할 수 있습니다. 즉, 전달받은 값에 따라 다른 객체를 생성하고, 인스턴스의 타입 등을 결정합니다.

다음은, 위에서 설명한 휴대폰 생산 공정을 예로 코드를 작성해보겠습니다.

class IPhone {
	constructor(){
    	this.name = 'iphone';
    }
}

class APhone {
	constructor(){
    	this.name = 'Aphone'
    }
}

class IPhoneFactory {
	static createPhone() {
    	return new Iphone();
    }
}

class APhoneFactory {
	static createPhone(){
    	return new APhone();
    }
}

const factoryList = {IPhoneFactory, APhoneFactory};

class PhoneFactory {
	static createPhone(type){
    	const factory = factoryList[type];
      	return factory.createPhone();
    }
}

const main = () => {
  	// 아이폰을 생산한다.
	const phone = PhoneFactory.createPhone('IPhoneFactory');
  	// 휴대폰 이름을 부른다.
  	console.log(phone.name); // iphone
}

보이시나요? 상위 클래스인 PhoneFactory에서 중요한 뼈대를 결정하고 하위 클래스인 IPhoneFactory가 세부적인 내용을 결정하고 있습니다.

참고로 이는 의존성 주입(Dependency Injection, DI) 이라고도 볼 수 있습니다. PhoneFactory에서 인스턴스를 생성하는 것이 아닌, IPhoneFactory에서 생성한 인스턴스를 PhoneFactory에 주입하고 있기 때문이죠.

PhoneFactory가 의존성 주입자가 될 것이고, 메인모듈은 IPhoneFactory, APhoneFactory가 될 것입니다.
PhoneFactory가 A이고 IPhoneFactory, APhoneFactory가 B라고 한다면, B가 달라짐으로써 A가 달라지게 됩니다. 이는 A는 B에 의존성을 갖는다! 라고 할 수 있습니다.

PhoneFactory.createPhone() 메서드에 넘기는 인자에 따라 결과가 달라질 것이라는게 보이시나요?
처음에 말했듯 넘기는 데이터에 따라 다른 객체를 생성하겠죠?

만약 의존성을 주입하지않는다면 어떻게 될까요?

const main = () => {
  	// 아이폰을 생산한다.
	const phone = IPhoneFactory.createPhone();
  	// 휴대폰 이름을 부른다.
  	console.log(phone.name); // iphone
}

PhoneFactory는 의존성 주입자기 때문에 사라지게 되고,
이런 식으로 작성되겠죠?

의존성을 주입하게 되면 하위모듈에서는 PhoneFactory를 import하여 기능을 구현할 수 있지만
의존성을 주입하지않게되면 하위모듈에서는 필요에 의해 IPhoneFactory, APhoneFactory를 import해 사용함으로써 모듈 간 의존성이 커지겠죠. (결합도 증가)

만약 IPhoneFactory, APhoneFactory 외에 여러 메인모듈을 생성하거나, 수정할 일이 생긴다면 ..
프로젝트의 복잡성이 증가하게 될겁니다.

클래스 내부에 있는 static 키워드는 무엇인가요?

정적 메서드를 정의하는 키워드인데요, 정적 메서드를 정의하면 해당 클래스를 기반으로 객체를 만들지않고 메서드 호출이 가능하며, 해당 메서드에 대한 메모리 할당을 한 번만 할 수 있다는 장점이 있습니다. 메서드 생성에 대한 비용이 감소한다고 볼 수 있겠습니다.

긴 글 읽어주셔서 감사드리며, 다음엔 전략 패턴으로 찾아뵙겠습니다.
감사합니다.

profile
DX를 사랑하는 개발자

0개의 댓글