이 실습에서는 Adapter와 Facade 패턴을 통해 레거시 시스템 통합과 복잡한 서브시스템 단순화를 경험합니다.
실습 목표
- 레거시 시스템과 신규 시스템 통합
- 복잡한 서브시스템을 단순한 인터페이스로 래핑
- 외부 라이브러리 의존성 격리
- 다양한 데이터 소스 통합
실습 1: 결제 시스템 Adapter
요구사항
서로 다른 결제 API들을 통합된 인터페이스로 제공
코드 템플릿
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
| // TODO 1: 통합 결제 인터페이스 정의
public interface PaymentGateway {
PaymentResult processPayment(PaymentRequest request);
boolean refundPayment(String transactionId, BigDecimal amount);
PaymentStatus getPaymentStatus(String transactionId);
}
// TODO 2: 레거시 결제 시스템 (변경 불가)
public class LegacyPaymentSystem {
public boolean makePayment(String cardNum, double amount, String currency) {
// 기존 시스템 로직 (변경 불가)
return true;
}
public String checkStatus(String paymentId) {
return "SUCCESS";
}
}
// TODO 3: 외부 Payment API (다른 인터페이스)
public class ExternalPaymentAPI {
public PaymentResponse charge(ChargeRequest request) {
// 외부 API 응답
return new PaymentResponse();
}
}
// TODO 4: Adapter 구현
public class LegacyPaymentAdapter implements PaymentGateway {
private final LegacyPaymentSystem legacySystem;
// TODO: 인터페이스 변환 로직 구현
}
public class ExternalPaymentAdapter implements PaymentGateway {
private final ExternalPaymentAPI externalAPI;
// TODO: 외부 API 호출을 내부 인터페이스에 맞게 변환
}
// TODO 5: 통합 테스트
public class PaymentAdapterTest {
@Test
public void testLegacyAdapter() {
// TODO: 레거시 시스템 어댑터 테스트
}
@Test
public void testExternalAdapter() {
// TODO: 외부 API 어댑터 테스트
}
}
|
실습 2: E-commerce Facade
요구사항
복잡한 주문 처리 과정을 단순한 인터페이스로 제공
코드 템플릿
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| // TODO 1: 복잡한 서브시스템들
public class InventoryService {
public boolean checkAvailability(String productId, int quantity) { return true; }
public void reserveItems(String productId, int quantity) {}
}
public class PaymentService {
public PaymentResult processPayment(PaymentInfo info) { return null; }
}
public class ShippingService {
public String scheduleDelivery(Address address, List<String> items) { return "TRACK001"; }
}
public class NotificationService {
public void sendOrderConfirmation(String email, String orderId) {}
}
// TODO 2: E-commerce Facade 구현
public class EcommerceFacade {
private final InventoryService inventoryService;
private final PaymentService paymentService;
private final ShippingService shippingService;
private final NotificationService notificationService;
// TODO: 복잡한 주문 처리 과정을 하나의 메서드로 단순화
public OrderResult placeOrder(OrderRequest request) {
// TODO: 1. 재고 확인
// TODO: 2. 결제 처리
// TODO: 3. 배송 예약
// TODO: 4. 알림 발송
// TODO: 5. 결과 반환
return null;
}
// TODO: 기타 편의 메서드들
public boolean isProductAvailable(String productId, int quantity) {
// TODO: 단순한 재고 확인
return false;
}
}
|
실습 3: 데이터 소스 통합 Adapter
코드 템플릿
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| // TODO 1: 통합 데이터 접근 인터페이스
public interface DataRepository<T> {
T findById(String id);
List<T> findAll();
void save(T entity);
void delete(String id);
}
// TODO 2: 다양한 데이터 소스 어댑터들
public class DatabaseAdapter<T> implements DataRepository<T> {
// TODO: JPA/JDBC 어댑터 구현
}
public class RestApiAdapter<T> implements DataRepository<T> {
// TODO: REST API 호출을 데이터 접근으로 변환
}
public class FileSystemAdapter<T> implements DataRepository<T> {
// TODO: 파일 시스템 접근을 데이터 접근으로 변환
}
// TODO 3: 통합 데이터 서비스 Facade
public class UnifiedDataService {
private final Map<String, DataRepository<?>> repositories;
// TODO: 데이터 소스별 라우팅 로직
public <T> T getData(String source, String id, Class<T> type) {
// TODO: 적절한 어댑터 선택 후 데이터 조회
return null;
}
}
|
체크리스트
Adapter 패턴
Facade 패턴
통합 구현
추가 도전
- Two-way Adapter: 양방향 어댑터 구현
- Configurable Facade: 설정 가능한 파사드
- Async Facade: 비동기 처리 파사드
- Circuit Breaker: 장애 격리 메커니즘
실무 적용
Adapter 활용 사례
- 마이그레이션 중 시스템 통합
- 외부 API 래핑
- 데이터 포맷 변환
- 테스트 더블 구현
Facade 활용 사례
- 마이크로서비스 API Gateway
- 복잡한 비즈니스 로직 단순화
- 레거시 모듈 현대화
- SDK/라이브러리 설계
핵심 포인트: Adapter는 호환성 문제를 해결하고, Facade는 복잡성을 숨깁니다. 두 패턴 모두 시스템 간의 결합도를 낮추고 유지보수성을 향상시킵니다.