아무거나 개발공부/스프링 완전 정복

스프링 핵심 원리이해 - 객체 지향 설계 (2)

코드 살인마 2023. 3. 14. 23:33
728x90

새로운 정책 개발

다형성 활용을 잘한 코드라면 새로운 정책을 추가하는데 아무 문제 없음

하지만 새로운 정책 적용에 문제가 있음

  • 클라이언트 코드인 주문 서비스 구현체도 함께 변경필요
  • 클라이언트가 인터페이스뿐만아니라 구현체도 함께 의존 → DIP 위반

관심사의 분리

  • AppConfig는 구현 객체를 생성하고 연결하는 책임
  • AppConfig의 등장으로 기존의 클라이언트 코드에서 구현체를 생성할 필요가 없어짐
  • 결과적으로 클라이언트 객체는 자신의 역할을 실행하는 것만 집중, 권한이 줄어듬(책임이 명확해짐)

AppConfig 리팩토링

  • 구성 정보에서 역할과 구현을 명확하게 분리
  • 역할이 잘 들어남
  • 중복 제거

기존코드

public class OrderServiceImpl implements OrderService {

	// OrderService는 생성(new), 연결, 실행 등 다양한 책임이 있음
	// 인터페이스(DiscountPolicy)뿐만 아니라, 구현체(FixDiscountPolicy)에도 의존관계임
	// 만약 FixDiscountPolicy -> newDiscountPolicy로 변경한다면 FixDiscountPolicy 구현체를 사용하는 모든 코드를 수정해야함
	private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
...
}

리팩토링 코드

public class OrderServiceImpl implements OrderService {
		// 인터페이스에만 의존관계
		private final DiscountPolicy discountPolicy;
		//생성자 추가
		public OrderServiceImpl(DiscountPolicy discountPolicy) {
		        this.discountPolicy = discountPolicy;
		    }
...
}

public class AppConfig {
		// OrderService에 구현체(discountPolicy)를 주입하고 있음
    public OrderService orderService() {
        return new OrderServiceImpl(discountPolicy());
    }
	  
    public DiscountPolicy discountPolicy() {
		// 새로운 정책을 변경해야한다면, 이 부분만 수정하면 됌
//      return new FixDiscountPolicy();
        return new newDiscountPolicy();
    }
}

결론

  • AppConfig의 등장으로 애플리케이션은 크게 사용 영역과, 객체를 생성하고, 구성하는 영역으로 분리
  • 할인 정책을 변경해도 AppConfig가 있는 구성 영역만 변경하면 됨. 사용영역을 변경할 필요가 없음.

좋은 객체 지향 설계의 5가지의 원칙의 적용

SRP 단일 책임 원칙

한 클래스는 하나의 책임만 가져야 한다.

  • 기존 클라리언트 객체는 구현 객체 생성, 연결, 실행 등 다양한 역할과 책임이 있었음
  • AppConfig을 통해 관심사를 분리하여 클라이언트 객체는 실행하는 책임만 담당

DIP 의존관계 역전 원칙

프로그래머는 “추상화에 의존해야지, 구체화에 의존하면 안된다.” 의존성 주입은 이 원칙을 따르는 방법 중 하나다.

  • 새로운 정책을 개발하고, 수정하려고 하니 클라이언트 코드도 함께 변경해야 했다. (기존 클라리언트 코드는 구체화 구현 클래스에도 함께 의존한 상태)
  • AppConfig가 객체 인스턴스를 클라리언트 코드 대신 생성하여 클라이언트 코드에 의존 관계를 주입하여 DIP 원칙을 따랐다.

OCP

소프트웨어 요소는 확장에는 열려있으나 변경에는 닫혀 있어야 한다.

  • 다형성을 사용하고, 클라이언트가 DIP를 지키면 무한히 확장가능하다.
  • 애플리케이션을 사용 영역과 구성 영역으로 나눈다.
  • 소프트웨어 요소를 새롭게 확장해도 사용 영역의 변경은 닫혀 있다.