본문 바로가기

이펙티브 자바

[이펙티브 자바] 아이템 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라

사용하는 자원에 따라 동작이 달라지는 클래스에는 정적 유틸리티 클래스나 싱글턴 방식을 사용하는 경우가 자주 있는데 이는 적합하지 않다.

인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식인 의존 객채 주입 패턴이 좋다.

 

예시 : 

// 주문 처리를 담당하는 클래스
public class OrderProcessor {
    // 결제 서비스에 대한 의존성
    private final PaymentService paymentService;
    // 재고 서비스에 대한 의존성
    private final InventoryService inventoryService;

    // 생성자를 통한 의존 객체 주입
    // OrderProcessor는 PaymentService와 InventoryService의 구체적인 구현에 의존하지 않습니다.
    // 대신, 이 서비스들은 외부(예: 애플리케이션의 설정 부분)에서 주입됩니다.
    public OrderProcessor(PaymentService paymentService, InventoryService inventoryService) {
        this.paymentService = paymentService;
        this.inventoryService = inventoryService;
    }

    // 주문 처리 메서드
    public void processOrder(Order order) {
        // 결제 처리 시도
        if (paymentService.processPayment(order.getTotalPrice())) {
            // 결제 성공 시, 재고 업데이트
            inventoryService.updateInventory(order.getItems());
            System.out.println("Order processed successfully.");
        } else {
            // 결제 실패 시
            System.out.println("Payment failed.");
        }
    }
}

// 결제 처리를 위한 인터페이스
public interface PaymentService {
    boolean processPayment(double amount); // 결제 처리 메서드
}

// 재고 관리를 위한 인터페이스
public interface InventoryService {
    void updateInventory(List<Item> items); // 재고 업데이트 메서드
}

// 애플리케이션 실행 클래스
public class App {
    public static void main(String[] args) {
        // 결제 서비스와 재고 서비스의 구현체를 생성
        PaymentService paymentService = new CreditCardPaymentService(); // 실제 결제 서비스 구현체
        InventoryService inventoryService = new WarehouseInventoryService(); // 실제 재고 관리 서비스 구현체

        // OrderProcessor 인스턴스 생성 시, 의존 객체를 주입
        OrderProcessor orderProcessor = new OrderProcessor(paymentService, inventoryService);
        
        // 주문 처리
        orderProcessor.processOrder(new Order(/* 주문 정보 */)); 
    }
}

 

예시의 OrderProcessor 클래스를보면 OrderProecessor는 paymentService 와 inventoryService 인터페이스에 의존한다. 하지만 구체적인 구현에는 의존하지 않는다. 앱 실행 클래스를 보면 이 두 서비스의 구체적인 구현은 생성자를 통해 주입된다. 

 

결론 : 클래스가 내부적으로 하나 이상의 자원에 의존하고, 그 자원이 클래스 동작에 영향을 준다면 필요한 자원(혹은 그 자원을 만들어주는 팩토리를) 생성자에(혹은 정적 팩토리나 빌더에) 넘겨주자. = 의존 객체 주입 기법을 사용해 클래스의 유연성, 재사용성, 테스트 용이성을 개선해주자.