이전 게시글의 내용이 너무 간략하여 조금 더 이해하기 쉽게 구체적으로 정리할 필요성을 느꼈습니다...
다형성이란?
하나의 타입으로 여러 구현체를 동일한 방식으로 다룰 수 있는 성질!
PaymentProcessor processor = new PaypalProcessor();
processor.processPayment(1000);
PaymentProcessor
가 어떤 구현체인지 몰라도.processPayment()
를 호출할 수 있음- 동일한 인터페이스로 다양한 객체의 동작을 유연하게 처리할 수 있게 해주는 것이 다형성!
- 상속, 인터페이스 중 인터페이스가 실무에서 자주 쓰이기 때문에 아래부터는 인터페이스 기준으로 설명하겠습니다.
구현보다 인터페이스가 먼저다
- 인터페이스는 '무엇을' 할 지만 정의하고, 구현체는 '어떻게' 할 지를 결정합니다.
- 코드는 구체적인 구현이 아닌 추상화(인터페이스)에 의존합니다.
- 이를 통해 코드 간의 결합도를 낮추고, 변경이 용이해집니다.
예시 코드를 통한 설명
PaymentProcessor.java
// 결제 기능이 있는 객체는 반드시 이 메서드를 구현하도록!
public interface PaymentProcessor {
boolean processPayment(double amount); // '무엇을'만 정의
}
추상화된 결제 처리 인터페이스
CreditCardProcessor.java
// 신용카드 결제를 구현한 클래스
public class CreditCardProcessor implements PaymentProcessor {
@Override
public boolean processPayment(double amount) {
System.out.println("신용카드로 " + amount + "원 결제 처리");
return true;
}
}
PaypalProcessor.java
// 페이팔 결제 로직을 가진 또 다른 구현체
public class PaypalProcessor implements PaymentProcessor {
@Override
public boolean processPayment(double amount) {
System.out.println("페이팔로 " + amount + "원 결제 처리");
return true;
}
}
OrderStatus.java
public enum OrderStatus {
PAID, PAYMENT_FAILED
}
주문 상태를 나타내는 enum 열거형
Order.java
public class Order {
private Long id;
private double totalAmount;
private OrderStatus status; // PAID, PAYMENT_FAILED 같은 상태
public Order(Long id, double totalAmount) {
this.id = id;
this.totalAmount = totalAmount;
}
public Long getId() { return id; }
public double getTotalAmount() { return totalAmount; }
public OrderStatus getStatus() { return status; }
public void setStatus(OrderStatus status) { this.status = status; }
}
주문 데이터 객체
OrderService.java
// 핵심 비즈니스 로직: 결제 처리 후 상태 업데이트
public class OrderService {
private PaymentProcessor paymentProcessor;
// 인터페이스를 의존성으로 받아 유연한 구조
public OrderService(PaymentProcessor paymentProcessor) {
this.paymentProcessor = paymentProcessor;
}
public void checkout(Order order) {
boolean success = paymentProcessor.processPayment(order.getTotalAmount());
if (success) {
order.setStatus(OrderStatus.PAID);
} else {
order.setStatus(OrderStatus.PAYMENT_FAILED);
}
}
}
OrderService
는 인터페이스만 보고 작동!CreditCardProcessor
인지PaypalProcessor
인지는 모름!
Main.java
public class Main {
public static void main(String[] args) {
Order order = new Order(1L, 10000);
// 신용카드 결제 사용
PaymentProcessor creditCardProcessor = new CreditCardProcessor();
OrderService creditCardOrderService = new OrderService(creditCardProcessor);
creditCardOrderService.checkout(order); // 신용카드로 결제
// 페이팔로 결제
PaymentProcessor paypalProcessor = new PaypalProcessor();
OrderService paypalOrderService = new OrderService(paypalProcessor);
paypalOrderService.checkout(order); // 페이팔로 결제
}
}
다른 구현체지만 같은 방식으로 사용 가능 → 다형성의 핵심!
인터페이스 기반 설계의 장점
확장성
// 새로운 결제 수단 추가해도 기존 코드 수정 없음
public class KakaoPayProcessor implements PaymentProcessor {
@Override
public boolean processPayment(double amount) {
System.out.println("카카오페이로 " + amount + "원 결제 처리");
return true;
}
}
OrderService
는 전혀 손댈 필요 없음!
테스트 용이성
// 테스트 전용 구현체: 진짜 결제 대신 성공/실패만 시뮬레이션
public class MockPaymentProcessor implements PaymentProcessor {
private boolean shouldSucceed;
public MockPaymentProcessor(boolean shouldSucceed) {
this.shouldSucceed = shouldSucceed;
}
@Override
public boolean processPayment(double amount) {
System.out.println("테스트 결제: " + (shouldSucceed ? "성공" : "실패"));
return shouldSucceed;
}
}
// 단위 테스트 예시
@Test
public void testOrderCheckoutSuccess() {
PaymentProcessor mock = new MockPaymentProcessor(true);
OrderService service = new OrderService(mock);
Order order = new Order(1L, 1000);
service.checkout(order);
// assertEquals: 두 값이 같은지 비교
assertEquals(OrderStatus.PAID, order.getStatus());
}
실제 결제 없이 테스트 가능!
'Java' 카테고리의 다른 글
static (0) | 2025.04.06 |
---|---|
Java: Map 인터페이스 (0) | 2024.11.27 |
Java: Set 인터페이스 (0) | 2024.11.26 |
Java: List 인터페이스 (0) | 2024.11.25 |
Java: 컬렉션 프레임워크 기본 개념 (0) | 2024.11.24 |