팩토리
"특정 구현으로부터 객체의 생성을 분리"
가장 일반적인 디자인 패턴
팩토리는 함수일 뿐이라서 사용자에게 더 적은 유연성을 제공 (사용자 관점)
팩토리는 클로저를 활용하여 캡슐화를 강제하는데 사용 할 수 있음
1 객체 생성과 구현의 분리
JS는 단순성, 유용성, 작은 노출을 선호 => 함수형 방식 선호
객체 인스턴스 생성 시 실제로 new 연산자 / Object.create() 대신 팩토리 호출이 편하고 유연함
객체 생성과 구현을 분리
새 인스턴스의 생성을 감싸서 객체 생성시 더 많은 유연성과 제어를 제공 (프로그램 관점)
특정 조건에 따라 다른 유형의 객체를 반환할 수있음
클래스를 숨겨 확장이나 수정하는것을 막음
// 특정 유형의 객체에 바인딩
function createImage (name) {
return new Image(name);
}
const image = new Image(name);
// 위의 예를 더 작은 클래스로 분할
function createImage(name) {
if (name.match(/\.jpe?g$/)) {
return new ImageJpeg(name);
} else if (name.match(/\.gif$/)) {
return new ImageGif(name);
} ... else {
throw new Error("Unsupported format!");
}
}
2 캡슐화를 강제할 수있는 메커니즘
클로저로 캡슐화 메커니즘 사용 (팩토리)
* 캡슐화 : 외부 코드가 컴포넌트의 내부 핵심에 직접 접근하여 조작하는것을 방지하기 위해 접근을 제어하는 것
컴포넌트와의 상호작용은 오직 공용(public) 인터페이스를 통해서 가능
컴포넌트의 상세 구현은 변경으로부터 외부코드를 분리시킬수 있다.
* 객체지향의 기본 원칙 : 상속, 다형성, 추상화, 캡슐화
캡술화 방법 : 스코프(scope) / 클로저 (clouser)
팩토리는 쉽게 프라이빗(private) 변수를 강제 할 수 있음
function createPerson (name) {
// privateProperties 객체 : 외부에서 접근 불가, person 객체가 제공하는 인터페이스만을 통해 접근 가능
const privateProperties ={};
// person 객체 : 팩토리가 반환하는 퍼블릭 인터페이스
const person = {
setName (name) { // name 속성을 강제화, name이 person 객체의 일반 속성이었다면 강제화 불가
if (!name) {
throw new Error("A person must have a name");
}
privateProperties.name = name;
},
getName () {
return privateProperties.name;
}
}
person.setName(name);
return person;
}
* 캡슐화 규약
private 필드 맨 앞을 # 기호로 시작
변수 앞에 _ 붙이기
3 간단한 코드 프로파일러 만들기
class Profiler {
constructor (label) {
this.label = label;
this.lastTime = null;
}
start () {
this.lastTime = process.hrtime();
}
end () {
const diff = process.hrtime(this.lastTime);
console.log(`Timer "${this.label}" took ${diff[0] seconds ` + `and ${diff[1]} nanoseconds.`);
}
}
프로덕션의 경우 위의 프로파일러를 비활성
이를 위해서 new 연산자를 사용해 Profile 객체를 직접 인스턴스화 하기 위해 다른 로직으로 분기
또는 팩토리 사용, 객체 생성을 추상화하고 모드별로 분기
const nonPrifiler = {
start () { ... },
end () { ... }
}
// createProfile()은 팩토리 함수, profiler 객체의 생성을 추상화함
export function createProfiler (label) {
if (process.env.NODE_ENV === "production") {
return nonPrifiler;
}
return new Profiler(label);
}
동적 타이핑으로 상황따라 객체를 선택
* 덕타이핑 : 어떤 상황에서 new 연산자로 인스턴스화된 객체를, 다른 상황에서는 간단한 객체 리터럴을 반환
원하는 방식으로 객체를 생성하는 방법을 보여줌
추가적인 초기화 단계를 실행하거나 특정 조건에 따라 다른 유형의 객체를 반환 할 수있음
이 모든 작업은 세부 사항들로부터 사용자를 분리함으로써 가능
최종 실행 예제를 봅시다.
// index.js
import {createProfiler } from './profiler.js';
function getAllFactors (intNumber) {
const profiler = createProfiler(`Finding all Factors of ${intNumber}`);
profiler.start();
const factors=[];
for (let factor = 2; factor <= intNumber; factor++) {
while ((intNumber % factor) === 0) {
factors.push(factor);
intNumber = intNumber /factor;
}
}
profiler.end();
return factors;
}
const myNumber = process.argv[2];
const myFactors = getAllFactors(myNumber); // 환경 변수 기반으로 생성되는 Profiler 객체
console.log(`Faoctrs of ${MyNumber} are : `, myFactors);
Summary
팩토리는 매우 일반적이 패턴이오.
Ex) Knex의 SQL 쿼리 빌더 - 단순히 팩토리 함수 하나만을 제공
팩토리로 다양한 검사를 수행, 데이터베이스 엔진에 맞는 dialect 객체를 선택하고 Knex 객체를 생성하여 반환
'Javascript > Node.js' 카테고리의 다른 글
Wiring Pattern - 생성자 디자인 패턴 (0) | 2022.02.03 |
---|---|
Singleton Pattern - 생성자 디자인 패턴 (0) | 2022.02.03 |
Domenic Revealing Constructor Pattern - 생성자 디자인 패턴 (0) | 2022.02.03 |
Builder Pattern - 생성자 디자인 패턴 (0) | 2022.02.03 |
디자인 패턴 (0) | 2022.02.03 |
댓글