본문 바로가기
프로그래밍언어/Java

[Java] DIP, OCP 원칙

by Yikanghee 2022. 1. 17.

DIP, OCP 원칙

DIP(Dependency Injection) 과 OCP (Open Closed Principle)은 스프링 프로젝트에서 관심사 분리를

통해 보다 훌륭한 프로젝트를 만드는 것을 도와준다

코드를 통해 *DIP, *OCP를 알아보자

  • 커피점에서 커피값을 할인할 때 할인정책을 정역할인해줄지, 퍼센테이지로 할인해줄지 아직
  • 정해지지 않았다
  • 이때, 다형성을 이용하여 기능 구현을 하면 두개의 기능을 만들어놓고 끼워 넣기만 하는 상황이된다
  • 위에 같은 상황일때, 구현 객체 코드에서 변경이 생기면 OCP 정책에 위반하게 된다
  • 이 상황을 해결하기 위해서 외부 의존관계 주입을 통해 해결한다.

*프로그래머는 “추상화에 집중해야지, 구현화에 집중해서는 안된다”

*소프트웨어 개체(클래스, 모듈 등) 은 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀야함

클라이언트 → 주문 생성 → 주문 서비스 수행 → 할인 정책 수행

위에 순서로 코드 진행이지만 이해를 위해 주문 서비스 수행과 할인 정책 수행 코드만 살펴보겠다

public class OrderServiceImpl implements OrderService {

    private final MemberRepository memberRepository = new MemoryMemberRepository()
    private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
		//다형성은 지켰지만 DI원칙을 지키지 못했고
		//변경 시 OCR원칙을 지키지 못한다
    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId); 
				//기존에 있던 회원 정보를 가져온다
        int discountPrice = discountPolicy.discount(member, itemPrice);
				//불러온 기존 회원 정보와 가격을 객체에 넣어주면 할인가격이 나온다

        return new Order(memberId, itemName, itemPrice, discountPrice);
    }
}

위 코드에 경우 인터페이스가 객체를 직접 설정하는 일이 생기게되어 DI 원칙에 위배된다

public class OrderServiceImpl implements OrderService {

    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int discountPrice = discountPolicy.discount(member, itemPrice);

        return new Order(memberId, itemName, itemPrice, discountPrice);
    }
}

DIP 원칙을 지키기 위해서 생성자를 만들어 의존관계를 설정할 수 있다

이 경우 Config 파일을 만들어서 의존객체를 주입해주어야한다

이것을 DIP라고 하며 자연스럽게 OCP원칙이 지켜지게된다

public class AppConfig{
	public MemberService memberService() {
        return new MemberServiceImpl(new MemoryMemberRepository());
    }
		
    public OrderService orderService(){
        return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
    }
}

위와 같이 의존객체를 주입해줄수있다

public class AppConfig {

    public MemberService memberService() {
        return new MemberServiceImpl(MemberRepository());
    }

    private MemoryMemberRepository MemberRepository() {
        return new MemoryMemberRepository();
    }

    public OrderService orderService(){
        return new OrderServiceImpl(MemberRepository(), discountPolicy());
    }

    private DiscountPolicy discountPolicy() {
//        return new FixDiscountPolicy();
        return new RateDiscountPolicy();
    }
}

리펙터링하여 보면 위와 같이 된다

만약 할인 정책을 변경 해야할 경우 주석처리 하여 사용할 수 있다

이때, 인터페이스인 OrderImpl에서 변경이 일어나지 않고 Config인 외부의 변경으로 의존객체가

변경이 되는것이 OCP정책을 지킨 개발이다

또한, Config 클래스를 IoC컨테이너, DIP컨테이너, 어셈블러, 오브젝트 팩토리 라고 부른다

댓글