무던하게

이전 게시글의 내용이 너무 간략하여 조금 더 이해하기 쉽게 구체적으로 정리할 필요성을 느꼈습니다...

다형성이란?

하나의 타입으로 여러 구현체를 동일한 방식으로 다룰 수 있는 성질!

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
profile

무던하게

@moodone

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!