Basic#2 OCP/DIP
2. OCP/DIP
Spring framework가 등장하게된 계기에 대해서 살펴보고자 한다. 우선 이번 section에서는 spring framework를 사용하지 않고 순수 자바로만 구현했을 때 상황을 예제를 통해 살펴본다.
1. 순수 Java로 구현한 서비스
- ISP 원칙을 지키기 위해서 인터페이스와 구현체를 분리한다.
public interface OrderService {
Order createOrder(Long memberId, String itemName, int itemPrice);
}
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository = new MemoryMemberRepository();
private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
@Override
public Order createOrder(Long memberId, String itemName, int itemPrice) {
...
}
MemberRepository
와 DiscountPolicy
도 인터페이스이며, 이를 각각 구현한 것이 MemoryMemberRepository
와 FixDiscountPolicy
다.
상황1 : 할인률 정책 변경
기존 정액 할인율(FixDiscountPolicy)
에서 정률 할인율(RateDiscountPolicy)
로 비즈니스 기획이 변경되었다고 가정한다. 앞서 ISP 원칙을 지켰기 때문에 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 위배 : 인터페이스에 의존해야하고 구현체에는 의존하지 말아야한다. →
new
를 통해 구현체와 의존 관계가 발생
2. 그럼 어떻게 Mapping?
위의 문제를 보고 그럼 어떻게 인터페이스와 구현체를 분리하면서 이들을 mapping할 수 있을까?라는 생각이 들 것이다.
이때 SRP를 고려하여 문제를 해결한다. (SRP : 하나의 클래스는 하나의 책임)
즉, AppConfig
파일을 통해서 DI를 담당하는 구현체를 만든다. 그리고 각각의 구현체는 인터페이스만 알게 한다. (OCP/DIP 준수)
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
public DiscountPolicy discountPolicy() {
// return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
각각의 구현체에서는 new
를 통해 직접 할당하지 않고, 인터페이스만 선언하여 사용한다.
public class OrderServiceImpl implements OrderService{
// private MemberRepository memberRepository = new MemoryMemberRepository();
// private DiscountPolicy discountPolicy = new FixDiscountPolicy();
// private DiscountPolicy discountPolicy = new RateDiscountPolicy();
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
만약 상황1
이 다시 발생한다면, 해당 할인 정책에 대한 구현체를 AppConfig
파일에서 mapping시켜주면 다른 구현체의 수정없이 동작할 수 있다.
따라서, SRP, OCP, DIP, ISP를 모두 만족하면서 개발을 할 수 있다. (=객체지향의 특성을 모두 살릴 수 있다.)
3. 정리
AppConfig
가 기존 개발자가 제어하던 흐름을 담당하여 처리하기 때문에 제어의 역전이 발생하며 IoC 컨테이너 또는 DI 컨테이너 라고 불린다. 이 AppConfig
가 확장된 것이 결국은 Spring framework다.
물론 spring framework로 전환하려면 일부 annotation이 추가된다.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public DiscountPolicy discountPolicy() {
// return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
또한 main에서는 각 구현체를 Bean
으로 가져와서 사용하면 된다.
public class MemberApp {
public static void main(String[] args) {
// Java
// AppConfig appConfig = new AppConfig();
// MemberService memberService = appConfig.memberService();
// Spring framework
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
Member member = new Member(1L, "memberA", Grade.VIP);
memberService.join(member);
Member findMember = memberService.findMember(member.getId());
System.out.println("find member = "+ findMember.getName());
}
}
Annotation이 붙으면서 뭔가 더 추가된 듯 하지만 그 이점에 대해서는 다음 장에서 알아본다.
🛠 계속 업데이트 필요
2022.03.25 최초 작성
Author And Source
이 문제에 관하여(Basic#2 OCP/DIP), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@dev2danis/Spring-Basic2-OCPDIP저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)