티스토리 뷰

Java

[Java] DIP (Dependency Inversion Principle)

snail voyager 2025. 3. 3. 20:32
728x90
반응형
고수준 모듈(High-level Module)은 저수준 모듈(Low-level Module)에 의존해서는 안 된다.
둘 다 추상화(인터페이스 또는 추상 클래스)에 의존해야 한다.

 

DIP를 위반한 코드 (Bad Code)

class EmailNotification {
    void sendEmail(String message) {
        System.out.println("이메일 전송: " + message);
    }
}

class NotificationService {
    private EmailNotification emailNotification = new EmailNotification();

    void notifyUser(String message) {
        emailNotification.sendEmail(message);
    }
}
  • NotificationService는 EmailNotification에 직접 의존 → EmailNotification을 변경하면 NotificationService도 변경해야 함
  • 만약 SMSNotification을 추가하고 싶다면? 기존 클래스를 수정해야 함 → OCP(개방/폐쇄 원칙)도 위반
  • 유지보수 및 확장성이 떨어짐

DIP를 적용한 코드 (Good Code)

// 1. 추상화 (인터페이스) 정의
interface Notification {
    void sendMessage(String message);
}

// 2. 구체적인 구현 클래스들 (Low-level 모듈)
class EmailNotification implements Notification {
    public void sendMessage(String message) {
        System.out.println("이메일 전송: " + message);
    }
}

class SMSNotification implements Notification {
    public void sendMessage(String message) {
        System.out.println("SMS 전송: " + message);
    }
}

// 3. High-level 모듈이 인터페이스에 의존하도록 변경
class NotificationService {
    private Notification notification;

    // 의존성 주입 (Dependency Injection)
    public NotificationService(Notification notification) {
        this.notification = notification;
    }

    void notifyUser(String message) {
        notification.sendMessage(message);
    }
}

// 4. 클라이언트 코드
public class Main {
    public static void main(String[] args) {
        Notification email = new EmailNotification();
        Notification sms = new SMSNotification();

        NotificationService emailService = new NotificationService(email);
        NotificationService smsService = new NotificationService(sms);

        emailService.notifyUser("안녕하세요! 이메일 알림입니다.");
        smsService.notifyUser("안녕하세요! SMS 알림입니다.");
    }
}
  • NotificationService는 Notification 인터페이스에 의존하므로 EmailNotification이나 SMSNotification의 변경이 필요 없음
  • 새로운 PushNotification을 추가할 때 기존 코드를 수정하지 않고 확장 가능 → OCP(개방/폐쇄 원칙)도 충족
  • NotificationService가 특정 구현체에 의존하지 않으므로, 필요할 때 유닛 테스트에서 Mock 객체를 주입하여 테스트 가능

DIP의 핵심 개념

DIP를 지키기 위해서는 의존성 주입 (Dependency Injection, DI)이 필요합니다.

의존성 주입(DI)란?

객체가 직접 다른 객체를 생성하는 것이 아니라, 외부에서 생성된 객체를 주입받아 사용하는 방식

  • DIP를 적용하기 위해 필수적으로 사용되는 패턴
  • Java에서는 생성자 주입, 필드 주입, 메서드 주입 방식이 있음

생성자 주입

class NotificationService {
    private Notification notification;

    public NotificationService(Notification notification) {
        this.notification = notification;
    }

    void notifyUser(String message) {
        notification.sendMessage(message);
    }
}

스프링 프레임워크를 활용한 DI 예제

@Component
class EmailNotification implements Notification {
    public void sendMessage(String message) {
        System.out.println("이메일 전송: " + message);
    }
}

@Service
class NotificationService {
    private final Notification notification;

    @Autowired
    public NotificationService(Notification notification) {
        this.notification = notification;
    }

    public void notifyUser(String message) {
        notification.sendMessage(message);
    }
}
  • Spring Framework의 @Autowired를 활용하면 객체 생성을 자동으로 주입
  • 실행 시점에서 Notification 인터페이스의 구현체(예: EmailNotification)가 자동으로 연결됨

DIP를 적용하면 얻을 수 있는 이점

  • DIP를 따르면 유연하고 확장 가능한 코드를 작성할 수 있음
  • DIP를 지키면 객체 간 결합도를 낮추고, 유지보수성이 뛰어난 코드를 만들 수 있음
  • 테스트가 어려운 문제를 해소할 수 있음
  • DIP를 따르면 OCP가 자연스럽게 적용됨 (기존 코드를 변경하지 않고 확장 가능)
  • ISP(인터페이스 분리 원칙)과도 연관됨 (불필요한 의존성을 최소화)

Domain Driven Development 에서 DIP

DIP를 잘못 적용한 예

  • 저수준 모듈에서 인터페이스를 추출하는 경우 잘못된 구조
  • 고수준 모듈(도메인 영역)이 저수준 모듈(인프라)에 의존하고 있음

DIP를 적용할 때 하위 기능을 추상화한 인터페이스는 고수준 모듈 관점에서 도출해야 한다.

  • 인프라에 위치한 클래스가 도메인이나 응용 영역에 정의한 인터페이스를 상속받아 구현하는 구조가 됨
  • 도메인과 응용 영역에 대한 영향을 주지 않거나 최소화하면서 구현 기술을 변경하는 것이 가능

 

728x90
반응형

'Java' 카테고리의 다른 글

[Java] Bounded WildCard  (1) 2025.03.03
[Java] Generic  (0) 2025.03.03
[Java] try-with-resources  (0) 2025.03.01
[Java] JSON Jackson @JsonProperty  (0) 2025.02.24
[Java] OpenCSV  (0) 2025.01.26
반응형
300x250