Spring

Spring - 역할과 구현, 의존 관계 주입의 필요성

소년조 2023. 3. 16. 17:59
역할과 구현

  역할 : 인터페이스

  구현 : 인터페이스를 구현한 클래스, 객체

 

예시

주문을 결정하는 인터페이스 OrderService 의 구현 클래스 OrderService 가 있습니다.

할인율을 결정하는 인터페이스 DiscountPolicy 의 구현 클래스 FixDiscountPolicy RateDiscountPolicy 가 있습니다.

 

 

OrderServiceimpl 클래스가 할인율을 정하기 위해 할인율 결정 역할을 가져와 사용하고 싶습니다.

먼저 고정 할인율을 적용한다면 아래와 같이 구현하면 됩니다.

 

public class OrderServiceimpl implements OrderService {
	private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
}

 

 

하지만 개발 진행 중 할인율 정책을 고정 할인율에서 비율 할인율로 바꾼다면 어떻게 될까요?

아래와 같이 적용했던 클라이언트 코드를 찾아 일일이 수정해야 합니다.

 

public class OrderServiceimpl implements OrderService {
	private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
}

 

 

이는 로버트 마틴의 객체 지향 설계 5가지 원칙 SOLID OCPDIP 를 위반합니다.

 

OCP (Open Closed Principle) 위반
  • 구현 객체를 변경하려면 클라이언트 코드 수정이 필요
    • new FixDiscountPolicy(); -> new RateDiscountPolicy();
DIP (Dependency Inversion Priniciple) 위반
  • 구현체new RateDiscountPolicy() 의존 ( 참조를 하든 생성을 하든 모두 의존이라 표현합니다 )
    • private final DiscountPolicy discountPolicy = new RateDiscountPolicy();

 

 

또한 해당 설계 방식은 OrderServiceimpl 클래스가 주문 관련 책임도 수행하고 어떤 할인을 적용할 지의 책임도 수행하고 있습니다. 즉, 여러 책임을 수행하므로 SRP(Single Responsibility Principle) 원칙도 잘 지켜지지 않고 있는데요.

 

이러한 문제를 Dependency Injection 을 활용해서 한 번에 해결할 수 있습니다.

 

 

DI (Dependency Injection )
Public class OrderServiceImpl implements OrderService {
	private final DiscountPolicy discountPolicy;
	public OrderServiceImpl (DiscountPolicy discountPolicy) {
		this.discountPolicy = discountPolicy;
	}
}

먼저 OrderServiceimpl 클래스 코드를 확인해보겠습니다.

 

OrderServiceimpl 클래스 코드를 위와 같이 수정함으로써 현재 할인률 정책이 고정 할인율인지 비율 할인율인지 알 필요가 없이 생성자 파라미터로 할인율 관련 객체를 전달 받아 쓰기만 하면 됩니다.

 

할인율 정책이 변화해도 내부 코드를 수정할 필요가 없고, 구현체를 의존하지도 않고 있습니다.

 

이렇게 역할과 구현을 분리하여 유연한 변경이 가능하게 할 수 있습니다.

 

 

그럼 어떤 할인율을 적용할 지는 어떻게 결정할까요?

 

바로 할인율 적용을 결정하는 설정 클래스를 만들면 됩니다.

 

 

AppConfig :  설정 클래스

AppConfig 는 위와 같은 각 역할들이 자신의 책임만 온전히 수행할 수 있도록 역할들의 연결을 설정해주는 클래스입니다.

public class AppConfig {
	public OrderService orderService() {
		return new OrderServiceImpl(new FixDiscountPolicy());
    }
}

위와 같이 구현 객체를 생성하여 필요한 객체의 생성자 파라미터로 연결해줍니다.

 

앞서 생성하고 참조하는 역할을 "의존" 이라고 표현하였습니다.

 

이렇게 AppConfig와 같은 클래스를 통하여 다른 클래스들이 자신의 역할만을 할 수 있도록 외부에서 의존 관계를 설정해주는 방식을 의존 관계 주입, Dependency Injection 이라고 합니다.