자원을 직접 명시하지 말고 의존 객체를 주입을 사용하라(Effective Java).

Choizz·2023년 7월 16일
0

이펙티브 자바

목록 보기
5/13

오늘은 이펙티브 자바 중 "자원을 직접 명시하지 말고 의존 객체를 주입을 사용하라"라는 내용에 대해 포스팅하도록 하겠습니다.


'자원을 직접 명시하지 말고'

자원을 직접 명시하지 말고에 대한 의미에 대해 생각을 해봐야할 것 같습니다.

  • new 생성자를 사용하는 경우를 예로 들수 있습니다.
  • 즉, 클라이언트 코드에서 new 생성자를 사용해서 직접 객체를 생성하고 사용하는 것을 의미합니다.
public class Test{
	
    //new 생성자에 의존
	private Test2 test2 = new Test2();
	
    //...
}
    

직접 명시했을 경우 왜 좋지 않을까?

  • 대표적으로, 객체 간의 의존성이 강해지는 경우를 들 수 있을 것 같습니다.
  • 위의 코드처럼 new 생성자를 이용해서 객체 간 의존관계가 형성되는 경우를 보면,
    • 코드 변경 시 클라이언트 코드를 직접 다른 객체로 바꿔주어야합니다.
      • private Test2 test2 = new Test2();
        private Test2 test2 = new Test3();
  • 결국, OCP 원칙을 지키지 못해 확장성이 떨어지게 될 것입니다.

의존 객체 주입을 사용하라.

의존 객체 주입을 사용하라라는 의미에 대해서 생각을 해보겠습니다.

  • 의존 객체를 주입한다는 것은 객체를 생성할 때, 생성자에 매개변수로 객체를 직접 넘겨주는 방법을 이야기 합니다.
  • 물론, setter 등을 통해서 객체를 주입해주는 방법도 있을 수 있습니다.
public interface Engine{
	void getName();
}
public class Engine1 implements Engine{	
}
public class Engine2 implements Engine{
}
public class Car{
    
	private Engine engine;
    
    //생성자를 통한 객체 주입
    public Test(Engine engine){
    	this.Engine = engine;
    }
	
    //...
}

---

//Test 객체를 생성할 때, Test2 객체를 주입한다.
public static void main(String[] args){
	Car newCar = new Car(new Engine1());
}
  • 위 코드처럼 Car 클래스에서 new 생성자를 사용해서 객체를 직접 생성하는 것이 아닌,
    • 외부에서 객체 생성을 주입을 주입받고 있습니다.

  • 여기서 중요한 점은 Car가 가지고 있는 필드의 타입이 인터페이스 타입이어야 한다는 것 입니다.
    • 만약 객체 자체를 필드 값으로 가진다면, 직접 명시하는 것과 별다른 차이가 없을 것입니다.
    • 왜냐하면 인터페이스를 구현하는 의존 객체들이 Car 객체에 주입될 수 있고, 그래야 Car 객체의 코드 변경이 없을 것이기 때문입니다.

외부에서 객체를 주입하면 어떤 점이 좋을까?

- 클라이언트 코드의 확장성이 증가할 수 있습니다.

- 위 코드에서 Engine1 객체를 Engine2로 바꾼다고 해서 Car 객체의 코드는 변화가 전혀 없습니다.
- 단지, Car 객체를 생성할 때, new Engine2()를 주입해주기만 하면 됩니다.
  • 이것은 코드의 재사용성 측면에 있어서도 좋습니다.
    • Car 객체가 변경이 되지 않은 채로 기능들을 바꾸거나 확장할 수 있기 때문입니다.
  • 테스트 코드를 작성하는 경우에도 용이합니다.
    • 본래의 객체를 직접 사용하기에 리소스가 많이 드는 경우에 인터페이스를 사용하기 때문에 mock 객체를 만들기 좋기 때문입니다.
    • 예를 들어, Engine1 객체를 직접 사용하기에 메모리도 많이 들고, 리소스가 크다면, Engine 인터페이스를 구현한 임의의 mock Engine 객체를 만들어 사용할 수 있습니다.

cf) 생성자에 객체를 생성하는 팩토리를 넣어서 객체를 주입하는 방법도 있습니다.

의존 객체 주입의 단점은 없을까?

  • 관리해야할 클래스가 증가할 수 있을 것입니다.
    • Engine 인터페이스를 구현하는 객체가 많아질 수록 관리하기가 힘들어 질 수 있습니다.

  • 클라이언트 코드만 보고 어떤 객체가 주입되었는지 찾기 힘들 수 있습니다.
    • Car 클래스의 Engine 필드만 보고 Engine1이 주입된 것인지, Engine2가 주입된 것인지 알기 어렵습니다.

의존 객체 주입은 언제 사용하는 것이 좋을까?

조금 극단적인 예이기는 하겠지만, 위에서 들었던 Car 객체의 경우를 보면, Engine 필드의 객체가 상황에 따라 바뀔 수 있을 것 입니다.

  • 즉, 사용하는 자원(위의 예에선 Engine)에 따라 메서드의 동작이 달라지는 클래스(Car)의 경우 의존 객체를 주입하는 것이 좋은 선택일 것입니다.
  • 반면, 유틸리티 클래스나 싱글톤 객체는 의존 객체 주입을 할 필요가 없을 것 입니다. 하나의 객체에서 수행하는 메서드가 동일할 것이기 때문입니다.

정리

  • 의존 객체 주입은 OCP와 DIP를 지키는데 가장 기본적인 것이라고 생각합니다.
  • 그래야 코드의 유지, 보수, 확장에 용이해질 것이기 때문입니다.
  • 그래서, 의존 객체 주입이라는 것이 중요하기 때문에 의존 객체 주입 프레임워크 중 하나인 스프링을 사용하는 것이라고 생각합니다.

reference
- https://www.inflearn.com/course/%EC%9D%B4%ED%8E%99%ED%8B%B0%EB%B8%8C-%EC%9E%90%EB%B0%94-1/dashboard

profile
집중

0개의 댓글