[스프링 핵심원리 - 기본편 (김영한)] 강의를 수강 후 복습하는 글입니다😀
1. SRP 단일 책임원칙
"클래스는 오직 하나의 책임만 가져야 한다"
수정 전
package hello.core.member;
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository = new
MemoryMemberRepository();
public void join(Member member) {
memberRepository.save(member);
}
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
} }
현재 'MemberSrviceImple`은 객체 생성, 연결, 실행을 하는 다양한 책임을 가지고 있다.
=> SRP 위반
객체 생성, 연결을 다른 객체로 책임을 넘겨보자
수정 후
package hello.core.member;
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository){
this.memberRepository = memberRepository;
}
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
=> SRP, DIP 충족
의존 관계였던 `MemberRepository`를 외부에서 주입받으므로써, 객체 생성과 연결의 책임이 없어졌다. 현재의 'MemberSrviceImple`은 오로지 실행에만 집중할 수 있다.
또한 코드 어디서도 구현체를 사용하는 코드가 없다. 오로지 추상회에 의존하며 DIP원칙을 충족한다. 이로써 새로운 `MemberRepository`가 추가되더라도 해당 클래스는 코드 변경없이 새로운 저장소를 받아들일 수 있다.
이를 위해 '구현 객체를 생성'하고 '연결'하는 책임을 가지는 별도의 설정 클래스를 만든다! 애플리케이션의 전체 동작을 구성하기 위한 클래스이다.
package hello.core;
/*
애플리케이션의 전체 동작은 구성하기 위해 '구현 객체를 생성'하고 '연결'하는 책임을 가지는
별도의 설정 클래스
*/
@Configuration
public class AppConfig {
@Bean
public MemberService memberService(){
// 이로써 MemberServiceImpl은 구현체가 바뀌어도 코드 수정 필요가 없음 => DIP 원칙 지킴
return new MemberServiceImpl(getMemberRepository());
}
// 2개로 중복되어서 2번 고쳤어야 했는데, 여기만 고치면 됨
@Bean
private static MemoryMemberRepository getMemberRepository() {
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService(){
return new OrderServiceImpl(getMemberRepository(), discountPolicy());
}
@Bean
public DiscountPolicy discountPolicy(){
return new RateDiscountPolicy();
}
}
2. DIP 의존 관계 역전 원칙
"프로그래머는 추상화에 의존하고 구현체에 의존하면 안된다."
수정 전
package hello.core.member;
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository = new
MemoryMemberRepository();
public void join(Member member) {
memberRepository.save(member);
}
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
} }
구현체인 `MemoryMeberRepository`에 의존하고 있다. 언뜻 추상화에 의존하고 있는 것처럼 보이지만 사실 추상화, 구현체 둘 다 의존하고 있는 상황이다.
추상화에만 의존하도록 해보자.
수정 후
package hello.core.member;
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository){
this.memberRepository = memberRepository;
}
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
구현체 코드를 없앤다. 그러면 널포인터 에러가 난다. 누군가 생성해줘야 한다! 위에서 언급했던 AppCofing에서 객체를 생성 후 주입한다.
객체를 주입받기 위해선 `MemberServiceImpl`은 추상화에만 의존하고 있어야한다.
만약 구현체에 의존하고 있으면 변동사항이 생길 때 `MemberServiceImpl`코드도 수정하고 `AppCofing` 코드도 수정해야 한다. 오로지 추상화 인터페이스에 의존하고 있어야만 클라이언트의 코드 수정없이 새로운 사항을 추가할 수 있다.
3. OCP
"확장에는 열여있고 변경에는 닫혀있어야 한다.
다형성을 사용하고 DIP원칙을 지키면 된다.
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository;
private 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);
}
}
AppCofing가 객체를 생성 후 주입하기 때문에, 'OrderServiceImpl'은 아무런 코드 변경없이 실행될 수 있다. 이때 변경하는 것은 AppConfig의 `discountPolicy`의 객체 생성 코드이다.
package hello.core;
@Configuration
public class AppConfig {
@Bean
public MemberService memberService(){
//....
@Bean
public OrderService orderService(){
return new OrderServiceImpl(getMemberRepository(), discountPolicy());
}
@Bean
public DiscountPolicy discountPolicy(){
return new RateDiscountPolicy();
}
}
'IT 정보 > 스프링 부트' 카테고리의 다른 글
[Spring] h2적용 후 postman으로 테스트하기 (0) | 2024.02.22 |
---|---|
스프링 : 빈 등록하기 (0) | 2023.12.14 |