Java, 스프링 의존성 주입(DI)

cyr·2022년 7월 9일
1

의존성

  • 두 모듈(클래스) 간의 연결
  • 하나의 모듈이 다른 하나의 모듈을 사용하기 위해서 발생

의존성에서의 문제점

  • 하나의 모듈의 내용을 변경했을 때 다른 모듈도 변경해야하는 문제가 생길 수 있다.

추상화를 통한 의존성문제 완화

public interface DiscountPolicy {
    int discount(Member member, int price);
}


public class FixDiscountPolicy implements DiscountPolicy {
    @Override
    public int discount(Member member, int price) {
		... ... 
    }
}

public class RateDiscountPolicy implements DiscountPolicy{
    @Override
    public int discount(Member member, int price) {
		... ...
    }
}

public class OrderServiceImpl implements OrderService {
	private DiscountPolicy discountPolicy;
    public OrderServiceImpl() {
    // 	discountPolicy = new FixDiscountPolicy();
        discountPolicy = new RateDiscountPolicy();
    }
}

위와 같은 방법으로 결합도를 낮추고 의존성에 대한 문제를 어느정도 해결할 수 있다. 구현체의 내용이 어떻게 바뀌든 간에 생성하는 객체의 클래스명 만 바꾸어 주면 되기 때문이다.

하지만 여전히 코드 내부에서 클래스명을 지정해 줘야하기 때문에 의존성 문제에서 벗어나지 못했다.

의존성 주입

  • 의존성 주입 : 의존성문제를 해결하기 위해 의존관계를 외부에서 주입하는 것.
public interface DiscountPolicy {
    int discount(Member member, int price);
}


public class FixDiscountPolicy implements DiscountPolicy {
    @Override
    public int discount(Member member, int price) {
		... ... 
    }
}

public class RateDiscountPolicy implements DiscountPolicy{
    @Override
    public int discount(Member member, int price) {
		... ...
    }
}

public class OrderServiceImpl implements OrderService {
	private DiscountPolicy discountPolicy;
    public OrderServiceImpl(DiscountPolicy discountPolicy) {
        this.discountPolicy = discountPolicy;
    }
}


//	외부
public class AppConfig {
    public OrderService orderService() {
        return new OrderServiceImpl(new FixDiscountPolicy());
     //	return new OrderServiceImpl(new RateDiscountPolicy());
    }
}


// 내부
public static void main(String[] args) {
	AppConfig appConfig = new AppConfig();
	OrderService orderService = appConfig.orderService();
    ... ...
}

위와 같이 의존성에 관한 정보들을 모두 외부에서 주입할 수 있다. 이렇게 했을 때, 의존관계를 수정하기 위해 내부 코드를 손 댈 필요가 없어진다.

의존성 주입 방법

  1. 생성자 주입
    • 위에서 구현한 방법이 생성자 주입 방법이다. 여기서 말한 생성자는 아래에 적은 이 부분이다.
public class OrderServiceImpl implements OrderService {
	private DiscountPolicy discountPolicy;
    
    public OrderServiceImpl(DiscountPolicy discountPolicy) {
    	this.discountPolicy = discountPolicy;
    }
}

// 외부
public class AppConfig {
    public OrderService orderService() {
        return new OrderServiceImpl(new FixDiscountPolicy());
     //	return new OrderServiceImpl(new RateDiscountPolicy());
    }
}

클래스를 통해 객체를 생성할 때 어떤 의존관계를 가질 지 생성자를 통해 바로 지정하는 방법이다.

  1. setter 주입
    • setter를 통해 의존관계를 주입하는 방법
public class OrderServiceImpl implements OrderService {
	private DiscountPolicy discountPolicy;
    
    public setDiscountPolicy(DiscountPolicy discountPolicy) {
    	this.discountPolicy = discountPolicy;
    }
}

// 외부
public class AppConfig {
    public OrderService orderService() {
        return new OrderServiceImpl(new FixDiscountPolicy());
     //	return new OrderServiceImpl(new RateDiscountPolicy());
    }
}

의존관계 주입의 장점

  • 클래스 간의 결합도가 낮아져서, 유지보수가 용이해진다.
  • 클래스 간의 결합도가 낮아져서, 테스트하기 편해진다.
  • 확장이 용이하다.
  • 가독성이 높아진다.
profile
개발

0개의 댓글