Factory 패턴
- 객체를 직접 생성하지 않고 “팩토리(공장)”가 객체를 대신 만들어 준다고도 볼 수 있습니다. 따라서 어떤 객체가 생성되는지에 대해 세부 사항을 알 필요 없이 팩토리에서 객체를 요청하면 됩니다.
1. 사용이유
Factory
패턴을 사용하면 함수를 호출하는 것으로 객체를 만들어낼 수 있습니다.
new
키워드를 사용하는 대신 함수 호출의 결과로 객체를 만들 수 있는 것 입니다.
- 객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화하는 패턴이자 상속 관계에 있는 두 클래스에서 상위 클래스가 중요한 뼈대를 결정하고, 하위 클래스에서 객체 생성에 관한 구체적인 내용을 결정하는 패턴입니다.
2. 예
- 각각의 레시피(우유, 아메리카노 등) 들어있는 하위 클래스가 컨베이어 벨트를 통해 전달되고, 상위 클래스인 바리스타 공장에서 이 레피시들을 토대로 우유 등등을 생산하는 생산 공정을 생각하면 된다.
- 앱에 다수의 사용자를 추가해야 한다고 가정해 보겠습니다.
-
Factory
함수를 사용해fullName
메서드를 가진 객체를 만들어 반환하고 있습니다.
Factory
를 사용했을 경우
const createUser = ({ firstName, lastName, email }) => ({ firstName, lastName, email, fullName() { return `${this.firstName} ${this.lastName}`; } }); const user1 = createUser({ firstName: "John", lastName: "Doe", email: "john@doe.com" }); const user2 = createUser({ firstName: "Jane", lastName: "Doe", email: "jane@doe.com" }); console.log(user1); console.log(user2);
- new 없이도 user1과 user2 객체를 얻을 수 있습니다.
- new를 사용하거나 User라는 클래스 이름을 알 필요가 없게 되는 것입니다.
- 팩토리 패턴은 상대적으로 복잡한 객체 혹은 환경이나 설정에 따라 키와 값을 다양하게 설정해야 하는 객체를 만들어야 할 때 유용하게 사용할 수 있습니다.
const createObjectFromArray = ([key, value]) => ({ [key]: value, }) createObjectFromArray(['name', 'John']) // { name: "John" }
3. 장점
- 팩토리 패턴은 동일한 프로퍼티를 가진 여러 작은 객체를 만들어낼 때 유용합니다. 현재의 환경이나 사용자 특징적인 설정을 통해 원하는 객체를 쉽게 만들 수 있습니다.
- 상위 클래스에서 인스턴스 생성 방식에 대해 전혀 알 필요가 없기 때문에 많은 유연성을 가집니다.
- 리펙토링을 하더라도 한 곳만 고칠 수 있게 되니 유지 보수성이 증가합니다.
3. 단점
- 자바스크립트에서 팩토리 함수는 new 키워드 없이 객체를 만드는 것에서 크게 벗어나지 않습니다.
- 또한, ES6의 화살표 함수를 이용하면 간결하게 작은 팩토리 함수를 만들 수 있습니다.
- 그리고 대부분의 상황에서 객체를 일일히 만드는 것 보다. 클래스를 활용하는 편이 메모리를 절약하는데 더 효과적입니다.
class User { constructor(firstName, lastName, email) { this.firstName = firstName this.lastName = lastName this.email = email } fullName() { return `${this.firstName} ${this.lastName}` } } const user1 = new User({ firstName: 'John', lastName: 'Doe', email: 'john@doe.com', }) const user2 = new User({ firstName: 'Jane', lastName: 'Doe', email: 'jane@doe.com', })
4. 추가 예시
// Product interface class Car { constructor(model, year) { this.model = model; this.year = year; } getInfo() { return `This is a ${this.year} ${this.model}.`; } } // Factory class CarFactory { createCar(model, year) { return new Car(model, year); } } // Usage const carFactory = new CarFactory(); const myCar = carFactory.createCar("Tesla Model S", 2022); console.log(myCar.getInfo()); // Output: This is a 2022 Tesla Model S.
CarFactory는 Car의 인스턴스를 직접 생성하는 것이 아니라, Car 클래스에서 생성한 인스턴스를 주입받아 사용합니다.