이 글에서 얻는 것
- Factory 패턴으로 객체 생성을 유연하게 관리합니다.
- Strategy 패턴으로 알고리즘을 런타임에 교체합니다.
- Template Method 패턴으로 공통 로직을 재사용합니다.
- 각 패턴의 사용 시점과 트레이드오프를 판단할 수 있습니다.
0) 디자인 패턴은 “반복되는 설계 문제의 해결책”
디자인 패턴은 소프트웨어 설계에서 자주 발생하는 문제에 대한 검증된 해결책입니다.
GoF(Gang of Four) 패턴 분류:
- 생성 패턴: 객체 생성 메커니즘 (Factory, Builder, Singleton)
- 구조 패턴: 클래스/객체 조합 (Adapter, Decorator, Proxy)
- 행위 패턴: 객체 간 협력 (Strategy, Template Method, Observer)
이 글에서는 백엔드에서 가장 많이 쓰이는 3가지를 다룹니다.
1) Factory 패턴: 객체 생성을 캡슐화
“객체 생성 로직을 별도 클래스로 분리”
1-1) 문제 상황
// ❌ 클라이언트가 구체 클래스에 의존
public class PaymentService {
public void processPayment(String type, int amount) {
Payment payment;
if (type.equals("CARD")) {
payment = new CardPayment();
} else if (type.equals("BANK")) {
payment = new BankTransferPayment();
} else if (type.equals("PAYPAL")) {
payment = new PayPalPayment();
} else {
throw new IllegalArgumentException("Unknown payment type");
}
payment.pay(amount);
}
}
문제점:
- 새 결제 수단 추가 시 PaymentService 수정 필요
- if-else가 여러 곳에 중복
- OCP(개방-폐쇄 원칙) 위반
1-2) Factory Method 패턴 적용
// 인터페이스
public interface Payment {
void pay(int amount);
}
// 구현체들
public class CardPayment implements Payment {
@Override
public void pay(int amount) {
System.out.println("Card payment: " + amount);
}
}
public class BankTransferPayment implements Payment {
@Override
public void pay(int amount) {
System.out.println("Bank transfer: " + amount);
}
}
// Factory 클래스
public class PaymentFactory {
public static Payment createPayment(String type) {
switch (type) {
case "CARD":
return new CardPayment();
case "BANK":
return new BankTransferPayment();
case "PAYPAL":
return new PayPalPayment();
default:
throw new IllegalArgumentException("Unknown payment type: " + type);
}
}
}
// ✅ 사용
public class PaymentService {
public void processPayment(String type, int amount) {
Payment payment = PaymentFactory.createPayment(type); // Factory 사용
payment.pay(amount);
}
}
장점:
- 객체 생성 로직이 한 곳에 집중
- 클라이언트는 인터페이스만 의존
- 새 타입 추가 시 Factory만 수정
1-3) Spring에서의 Factory 패턴
// Spring이 Factory 역할
@Configuration
public class PaymentConfig {
@Bean
public Payment cardPayment() {
return new CardPayment();
}
@Bean
public Payment bankPayment() {
return new BankTransferPayment();
}
// 팩토리 메서드
@Bean
public PaymentFactory paymentFactory(List<Payment> payments) {
return new PaymentFactory(payments);
}
}
@Service
public class PaymentService {
private final PaymentFactory factory;
public PaymentService(PaymentFactory factory) {
this.factory = factory;
}
public void processPayment(String type, int amount) {
Payment payment = factory.getPayment(type);
payment.pay(amount);
}
}
💬 댓글