팩토리 패턴(factory pattern)
팩토리 패턴(Factory Pattern)은 객체 생성을 담당하는 디자인 패턴 중 하나입니다. 이 패턴은 객체를 생성하기 위한 인터페이스를 정의하고, 이 인터페이스를 통해 구체적인 객체의 생성을 서브클래스에게 위임하는 방식으로 동작합니다.
일반적으로, 클라이언트 코드에서는 어떤 클래스의 인스턴스를 직접 생성하는 대신에 추상화된 인터페이스를 통해 객체를 요청합니다. 이 추상화된 인터페이스는 팩토리 메서드로 정의되어 있습니다. 실제로 객체를 생성하는 작업은 구체적인 팩토리 클래스에서 수행됩니다. 각각의 구체적인 팩토리 클래스는 추상화된 인터페이스를 상속받거나 해당 인터페이스를 구현하여 실제 객체의 생성을 담당합니다.
팩토리 메서드 내부에서는 적절한 구체적인 제조자(Concrete Creator)가 선택되고, 선택된 Concrete Creator에서는 적절한 Concrete Product(구체적인 제조물)을 반환합니다. 클라이언트 코드는 실제로 어떤 클래스의 인스턴스가 만들어지는지 알 필요 없이, 단지 추상화된 팩터리와 그것으로부터 반환되는 제조된 제조물만 알면 됩니다. 따라서 클라이언트 코드와 실제 객체 생성 로직 사이의 결합도가 낮아지며 유연성과 확장성이 향상됩니다.
팩토리 패턴은 복잡한 조건문 대신에 간단하게 특정 타입의 객체를 만들기 위해 해당 타입에 맞는 컨크릿 크레에타(Creator)만 호출하면 되므로 코드 가독성도 개선됩니다.
자바스크립트의 팩토리 패턴
자바스크립트에서 팩토리 패턴을 구현한다면 아래처럼 구현할 수 있습니다.
// 제품(Product) 클래스
class Car {
constructor(name) {
this.name = name;
}
getInfo() {
return `This is a ${this.name} car.`;
}
}
// 팩토리(Factory) 클래스
class CarFactory {
createCar(name) {
return new Car(name);
}
}
// 클라이언트 코드
const factory = new CarFactory();
const car1 = factory.createCar("Sedan");
const car2 = factory.createCar("SUV");
console.log(car1.getInfo()); // 출력: This is a Sedan car.
console.log(car2.getInfo()); // 출력: This is a SUV car.
자바스크립트에서는 new Object()로 구현할 수 있습니다. 소스를 간단하게 살펴보겠습니다.
- Car 클래스는 제품을 나타내며, 생성자를 통해 이름을 받습니다. getInfo() 메서드는 해당 차량의 정보를 반환합니다.
- CarFactory 클래스는 팩토리 역할을 수행하며, createCar() 메서드를 통해 새로운 차량 객체를 생성합니다.
- 클라이언트 코드에서는 CarFactory 인스턴스를 생성하고, 해당 팩토리를 사용하여 createCar() 메서드로 차량 객체(car1, car2)를 생성합니다. 각각의 차량 객체에 대해 getInfo() 메서드를 호출하여 정보를 출력합니다.
자바의 팩토리 패턴
자바의 경우도 한 번 살펴보겠습니다.
// 제품(Product) 인터페이스
interface Car {
String getInfo();
}
// 구체적인 제품(Concrete Product)
class Sedan implements Car {
@Override
public String getInfo() {
return "This is a Sedan car.";
}
}
class SUV implements Car {
@Override
public String getInfo() {
return "This is an SUV.";
}
}
// 추상 팩토리(Abstract Factory)
interface CarFactory {
Car createCar();
}
// 구체적인 팩토리(Concrete Factory)
class SedanFactory implements CarFactory {
@Override
public Car createCar() {
return new Sedan();
}
}
class SUVFactory implements CarFactory{
@Override
public Care createCar(){
return new SUV();
}
}
// 클라이언트 코드
public class Main{
public static void main(String[] args){
CarFactory sedanFactory = new SedanFactor();
Car sedan = sedanFatory.createCar();
System.out.println(sedan.getInfo());
CarFacotry suvFacotry= new SuvFactor();
Car suv= suvFacotry.createcar();
System.out.println(suv.getinfo());
}
- 인터페이스인 Car는 제품을 나타내며, 각 구체적인 제품은 이 인터페이스(Car)를 구현합니다. 구체적인 제품으로는 Sedan과 SUV가 있습니다. 각각의 구체적인 제품은 자신에게 맞는 정보(getInfo())를 반환합니다.
- 추상 팩터리(CarFactory) 인터페이스에서는 공장 역할을 수행하는데, 여기에는 팩터리 메서드(createCar())가 포함됩니다.
- 구체적인 팩터리 클래스들(SedanFactory, SUVFactory)은 추상 팩터리 인터페이스(CarFactory)를 상속받아 실제 객체의 생성을 담당합니다. 각각의 구체적인 팩터리 클래스에서는 해당하는 종류의 차량 객체(구체적인 제조물)을 반환하는 방식으로 작성됩니다.
- 클라이언트 코드에서는 필요한 종류에 맞게 적절한 구체적인 팩터리(예: SedanFactory)로부터 객체(예: sedan)를 생성하고, 이렇게 만들어진 객체에 대해 정보 출력을 수행합니다.
팩토리 패턴은 클라이언트 코드와 실제 객체 생성 로직 사이의 결합도가 낮아지고 유연성과 확장성이 향상되며, 복잡한 조건문 없이도 특정 타입의 객체 생성이 가능하다는 장점이 있습니다.
전략 패턴(strategy pattern)
전략 패턴은 정책 패턴(policy pattern)이라고도 하며, 객체의 행위를 바꾸고 싶은 경우 직접 수정하지 않고 캡슐화한 알고리즘을 컨텍스트 안에서 바꿔주면서 상호 교체가 가능하게 만드는 패턴입니다.
Swift로 만든 전략 패턴에 대한 소스를 살펴보겠습니다.
// 전략을 위한 프로토콜 정의
protocol PaymentStrategy {
func pay(amount: Double)
}
// 신용카드 결제 전략의 구체적인 구현
class CreditCardPaymentStrategy: PaymentStrategy {
private let cardNumber: String
private let expirationDate: String
private let cvv: String
init(cardNumber: String, expirationDate: String, cvv: String) {
self.cardNumber = cardNumber
self.expirationDate = expirationDate
self.cvv = cvv
}
func pay(amount: Double) {
print("Paid \(amount) dollars with credit card \(cardNumber)")
}
}
// ApplePay 결제 전략의 구체적인 구현
class ApplePaymentStrategy: PaymentStrategy {
private let email: String
init(email: String) {
self.email = email
}
func pay(amount: Double) {
print("Paid \(amount) dollars with Apple account \(email)")
}
}
// 선택한 결제 전략을 사용하는 컨텍스트 클래스
class ShoppingCart {
private var paymentStrategy: PaymentStrategy
init(paymentStrategy: PaymentStrategy) {
self.paymentStrategy = paymentStrategy
}
func checkout(totalAmount: Double) {
paymentStrategy.pay(amount: totalAmount)
}
func changePaymentStrategy(newPaymentStrategy: PaymentStrategy) {
paymentStrategy = newPaymentStrategy
}
}
// 예제 사용법
let creditCardPayment = CreditCardPaymentStrategy(cardNumber: "1234-5678-9012-3456", expirationDate: "12/25", cvv: "123")
let ApplePayment = ApplePaymentStrategy(email: "example@example.com")
let cart = ShoppingCart(paymentStrategy: creditCardPayment)
cart.checkout(totalAmount: 100.0)
cart.changePaymentStrategy(newPaymentStrategy: ApplePayment)
cart.checkout(totalAmount: 50.0)
이 예제에서는 PaymentStrategy 프로토콜을 정의하고, 두 개의 구체적인 구현(CreditCardPaymentStrategy와 PayPalPaymentStrategy)을 만듭니다. ShoppingCart 클래스는 선택한 결제 전략을 사용하여 결제를 수행합니다. 쇼핑 카트에서 changePaymentStrategy 메서드를 호출하여 간편하게 다른 결제 전략으로 전환할 수 있습니다.
감사합니다.
틀린 부분이 있거나 더 좋은 내용 훈수 환영합니다!
공감과 댓글 부탁드립니다.
'CS > 디자인 패턴' 카테고리의 다른 글
[디자인패턴] MVC 패턴 이해하고 활용하기 (2) | 2024.01.15 |
---|---|
[디자인패턴] 이터레이터 패턴 With Swift, Java (0) | 2023.10.29 |
[디자인패턴] 프록시 패턴(Proxy Pattern) (2) | 2023.10.22 |
[디자인패턴] 옵저버 패턴(Observer Pattern) (2) | 2023.10.21 |
[디자인 패턴] 디자인 패턴과 싱글톤 패턴 (2) | 2023.05.24 |