JKROH 2023. 1. 29. 21:49
반응형

Main Point : 의존은 줄이되 필요하다면 주입하자.


- 의존

  • 의존은 기능 구현을 위해 다른 구성 요소를 사용하는 것이다.
  • 의존의 예시로는 객체를 생성하거나, 메소드를 호출 하는 것, 데이터를 사용하는 것 등이 있다.
  • 의존은 변경이 전파될 가능성을 의미한다. 즉, 의존하는 대상이 바뀌면 의존한 대상도 바뀔 가능성이 높아진다.
  • 예를 들어, 내가 호출하는 메소드의 파라미터가 변경되거나, 발생할 수 있는 예외 타입이 추가되는 경우가 있다.
  • Controller는 자신이 맡은 Domain 기능에 모두 의존하며 Domain 기능이 바뀌면 Controller의 코드도 수정해야 하는 경우를 생각하면 이해가 쉽다.

 

- 순환 의존

  • 순환의존은 변경의 연쇄 전파 가능성이 높기 때문에 위험하다.
  • 예를 들어 A클래스는 B에 의존하고, B는 C에 의존하고, C는 다시 A에 의존하는 A -> B -> C -> A 형태의 구조가 있다고 생각해보자.
  • 위의 경우에서 A의 변경은 B에 영향을 주지만, 의존을 타고(연쇄적으로 의존이 전파되고) 결국 A에 다시 영향을 주는 구조가 된다.
  • 코드 변경의 영향을 줄이고, 변경을 원할히 하기 위해서는 클래스, 패키지, 모듈 등 모든 수준에서 순환 의존이 없도록 해야한다.

 

- 의존 대상이 많다면

  • F라는 클래스가 A, B, C, D, E 다섯 개의 클래스에 모두 의존한다고 가정해보자.
  • A 클래스가 수정 되면 F 클래스도 바뀔 수 있다.
  • B 클래스가 수정 되면 F 클래스도 바뀔 수 있다.
  • 마찬가지로 C, D, E 클래스가 각각 변경되는 것은 모두 F 클래스에 영향을 준다.
  • 다시 말해, 의존 대상이 적어야 각 클래스 간의 영향이 줄고, 클래스의 변경 가능성이 줄어든다. 따라서 의존하는 대상은 적을수록 좋다.

 

- 의존 대상이 많을 때 : 기능이 많은 경우

  • 한 클래스에서 많은 기능을 제공하는 경우 의존 대상이 많을 수 있다.
  • 각 기능별로 의존하는 대상이 다를 수 있다. 또한 한 기능을 변경할 때 이것이 다른 기능에 영향을 줄 수도 있다.
  • 하나의 기능을 테스트하고 싶어도 나머지 기능에서 필요로 하는 대상까지 초기화 해야하는 경우가 발생할 수 있다. 즉, 테스트가 어려워진다.
  • 이런 경우에는 기능별로 클래스를 분리하는 것을 고려해봐야 한다. 클래스의 갯수는 증가하겠지만, 각 클래스마다 필요로하는 의존이 줄어들고, 한 기능을 수정할 때, 다른 기능과 관련된 코드를 수정하는 일이 발생하지 않는다. 또한 개별 기능을 테스트하는 것도 수월해진다.

 

- 의존 대상이 많을 때 : 묶어보기

  • 여러 의존 대상을 당일 기능으로 묶어볼 수 있는지 생각해보면 의존 대상을 줄일 수 있다.
  • 하나의 기능을 지나치게 많이 구분했을 때 이런 문제가 발생할 수 있다. 리팩토링 과정에서 다시 한 번 객체의 기능과 역할에 대해 고민하고 추상화를 진행하면서 의존 대상을 줄일 수 있다.

 

- 의존 대상 객체를 직접 생성

  • 생성 클래스가 바뀌면 의존하는 클래스의 코드도 바뀌게 된다.
  • 의존 대상 객체를 직접 생성하지 않는 방법
    • 팩토리, 빌더
    • 의존 주입 (Dependency Injection)
    • 서비스 로케이터 (Service Locator)

 

- 의존 주입

  • 의존하는 대상을 직접 생성하지 않고 대신에 생성자나 메소드를 이용해서 외부에서 의존 객체를 전달받는 방식이다.
  • 아래의 예시를 통해 알아보자.
public class Category {
    private final Menus menus;
    private String name;
    
    public Category(Menus menus) {
        this.menus = menus;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
 //초기화 코드
 Menus menus = new Menus(Arrays.asList("짜장면", "짬뽕", "탕수육"));
 String categoryName = "중식";
 
 Category chinese = new Category(menus);
 chinese.setName(categoryName);
더보기

 Category 클래스 내에서 다른 클래스의 객체를 생성하지 않고 외부에서 set메소드와 생성자를 통해 의존성을 주입한 코드이다. 

 

- 조립기

  • 조립기가 객체를 생성하고 의존 주입을 처리한다.
  • 대표적인 조립기로는 Spring 프레임워크가 있다.

 

- DI 장점

  • 의존 대상이 바뀌면 조립기의 설정만 변경하면 된다.
  • 의존하는 객체 없이 대역 객체를 사용해 테스트도 가능하다.

 

- DI를 습관처럼 사용하기

  • 의존이 반드시 필요한 경우라면 의존 객체는 주입받도록 코드를 작성하는 습관이 필요하다.
반응형