본문 바로가기

WINK-(Web & App)/Spring Boot 스터디

[2024-2 SprintBoot 스터디] 김아리 #4주차

반응형

상황 설명

기획자가 정액 할인제에서 정률 할인제로 정책을 바꿈

따라서 개발자는 주문 서비스 클라이언트(OrderServiceImpl)에서 DiscountPolicy를 FixDiscountPolicy에서 RateDiscountPolicy로 바꿈

public class OrderServiceImpl implements OrderService {
    private final MemberRepository memberRepository = new MemoryMemberRepository();
    // 직접 클라이언트 코드를 수정하여 사용하고자 하는 구현체와 연결
    private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
    private final DiscountPolicy discountPolicy = new RateDiscountPolicy();

--> 문제 발생 : OCP, DIP 원칙 위반

- DIP(의존관계 역전 원칙) : 추상(인터페이스) 뿐만 아니라 구현체에도 의존하고 있다.

- OCP(개방-폐쇄 원칙) : 확장은 열려 있으나 변경은 닫혀 있어야 한다. 지금 코드를 변경하면 클라이언트 코드에 영향을 준다.

 

관심사 분리

AppConfig 

- 전체 동작 방식 구성

- 실제 동작에 필요한 구현 객체 생성

- 생성한 객체의 레퍼런스를 생성자를 통해 연결(생성자 주입)

// 관심사 분리
public class AppConfig {
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }   
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
    public OrderService orderService() {
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    } 
    public DiscountPolicy discountPolicy() {
        return new RateDiscountPolicy();
    }
}

 

수정된 MemberServiceImpl

public class MemberServiceImpl implements MemberService{
    // DIP 원칙 충족
    private final MemberRepository memberRepository;
    // 생성자 주입
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

 

수정된 OrderServiceImple

public class OrderServiceImpl implements OrderService {
    // DIP 원칙 충족
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;
    // 생성자 주입
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }

--> 각 수정된 클라이언트 코드에서는 어떤 구현체를 사용했는지 알 수 없다.

 

제어의 역전 IoC(Inversion of Control)

- 프로그램에 대한 제어 흐름에 대한 권한은 모두 AppConfig가 가지고 있다.

- 실제 로직을 실행하는 서비스 구현체는 필요한 인터페이스만 호출할 뿐 어떤 구현 객체가 실행될 지 모른다.

- 이렇게 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것을 제어의 역전(IoC)라고 한다.

 

의존관계 주입 DI(Dependency Injection)

- 서비스 구현체는 인터페이스에 의존한다. 실제 어떤 구현 객체가 사용될지는 모른다.

- 의존 관계는 정적인 클래스 의존 관계와 실행 시점에 결정되는 동적인 객체(인스턴스) 의존 관계를 분리해서 생각해야 한다.

  --> 정적인 클래스의 의존 관계 : 클래스의 import 코드만 보고 판단 가능

  --> 동적인 객체 인스턴스 의존 관계 : 런타임에 외부에서 실제 구현 객체를 생성하고 클라이언트에 전달해서 클라이언트와 서버의 실제 의존 관계가 연결되는 것을 의존관계 주입이라고 한다.

- 이를 통해 정적인 클래스의 의존관계를 변경하지 않고 동적인 객체 인스턴스 의존관계를 쉽게 변경할 수 있다.

 

IoC 컨테이너, DI 컨테이너

- AppConfig처럼 객체를 생서하고 관리하면서 의존관계를 연결해 주는 것- 어샘블러, 오브젝트 팩토리 등으로 불리기도 한다.

반응형