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);
}
}
설계상 문제점은 아래와 같다.
private final MemberRepository memberRepository = new MemoryMemberRepository();
그 이유는 구현과 추상화에 모두 의존하기 때문에 OCP와 DIP를 모두 충족시키지 못한다.
MemberRepository는 인터페이스이므로 추상화에 의존하고,
MemoryMemberRepository는 클래스이므로 구현에도 의존한다.
기능이 확장되어 변경하면, 클라이언트 코드에 영향을 주므로 이는 OCP를 위반하는 것이다.
문제 해결 방안
결과적으로는 DIP도 위반하게 된다.
그러므로 이를 위반하지 않게 인터페이스에만 의존하게끔 의존관계를 변경하면 된다.
private MemberRepository memberRepository;
이렇게 수정하게 되면, 인터페이스에만 의존할 수는 있지만 구현체가 없다. 고로 Null Pointer Exception이 발생하게 된다.
결국 이 문제를 해결하기 위해서 MemberRepository 구현 객체를 대신 생성하고 주입하여야 한다.
관심사의 분리
책임을 분리하자는 의미와 같다.
연극에서 어떠한 역할 누가 할지는 배우가 정하는 것이 아닌, 연출자가 정하는 것이다.
하지만 private final MemberRepository memberRepository = new MemoryMemberRepository()는
마치 배우가 직접 공연하고 다른 배우도 초빙하는 다양한 책임을 가지고 있다고 볼 수 있다.
그러므로 우리는 기획자를 만들고, 기획자의 책임을 분명히 해야 한다.
결국 기획자가 필요하다.
구현객체를 생성하고 연결하는 책임을 가지는, 애플리케이션의 전체 동작방식을 구성하는 클래스를 생성하면 된다.
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
}
AppConfig는 실제 동작의 필요한 구현객체를 생성하며 생성자를 통해서 주입해 준다.
그러므로 생성자가 필요한 클래스에 생성자 함수를 생성해 주면 된다.
이렇게 설계 변경으로 더 이상 위의 클래스는 구현체에 의존하지 않는다.
public class MemberApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
~
}
'📑 개발 이론 > 🌱 SPRING' 카테고리의 다른 글
스프링 핵심 원리 - 스프링 빈 (0) | 2023.06.17 |
---|---|
스프링 핵심 원리 - 스프링 컨테이너 (0) | 2023.06.17 |
스프링 핵심 원리 - 객체지향 원리 적용 정리 (0) | 2023.06.17 |
[스프링 핵심원리] SOLID 원칙 (0) | 2023.04.18 |
[스프링 핵심원리] 객체지향프로그래밍이란? (0) | 2023.04.18 |