작성
·
342
0
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.
좋은 객체 지향 설계의 5가지 원칙(SOLID)에서 7:39초 부분인데요,
MemberService에 MemberRepository m;으로 변수를 선언해놓고 setMemberRepository(m) 메서드를 만들어서 main 메서드 등 외부에서 구현클래스를 할당해주면 MemberService 즉, 클라이언트 코드를 변경하지 않아도 되기 때문에 OCP 원칙을 지킬 수 있는 것 아닌가요? 지킬 수 없다는 것이 잘 이해가 안됩니다.
질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.
=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/아니오)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)
[질문 내용]
여기에 질문 내용을 남겨주세요.
답변 3
0
강의를 수강하지 않았지만 질문 주신 내용을 토대로 답변 남겨봅니다.
의존성 주입(DI)이 OCP와 DIP를 지원하는 기술이지만, DI를 사용한다고 해서 원칙들이 지켜지는 것은 아닙니다. OCP와 DIP 원칙을 제대로 적용하기 위해서는 설계에 대한 고민이 필요합니다.
MemberRepository
를 구체 클래스로 직접 의존할 경우, MemberService
는 MemberRepository
의 변화에 직접적인 영향을 받게 됩니다. 예를 들어, MemberRepository
를 NewMemberRepository
로 변경해야 할 때 MemberService
의 코드도 함께 수정해야 하는 상황이 발생합니다. 이는 OCP와 DIP 원칙을 위반하게 됩니다.
이 문제를 해결하기 위해서는 MemberRepository
의 인터페이스(추상화)를 정의하고, MemberService
가 이 인터페이스에 의존하도록 설계해야 합니다. 이렇게 하면 MemberService
는 MemberRepository
의 구체적인 구현에 독립적이 되어, 구현체가 변경되어도 MemberService
의 코드를 수정할 필요가 없어집니다.
이해를 위해 아래에 구체 클래스 의존과 인터페이스 의존의 예시 코드 남겨봅니다. DIP와 OCP 원칙에 대해 학습해보시고 직접 코드를 작성해보시면 금방 이해하실 수 있을거라고 생각합니다.
// OriginMemberRepository 사용
@Service
public class MemberService {
private OriginMemberRepository memberRepository; // DIP 위반
public void setMemberRepository(OriginMemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
@Repository
public class OriginMemberRepository {
public void save(String member) {
System.out.println("원래 구현체");
}
}
// OriginMemberRepository -> NewMemberRepository 변경
@Service
public class MemberService {
private NewMemberRepository memberRepository; // 코드 변경(OCP 위반)
public void setMemberRepository(NewMemberRepository memberRepository) { // 코드 변경(OCP 위반)
this.memberRepository = memberRepository;
}
}
@Repository
public class OriginMemberRepository {
public void save(String member) {
System.out.println("원래 구현체");
}
}
@Repository
public class NewMemberRepository {
public void save(String member) {
System.out.println("새로운 구현체");
}
}
// OriginMemberRepository 사용
@Service
public class MemberService {
private MemberRepository memberRepository;
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
public interface MemberRepository {
void save(String member);
}
@Repository
public class OriginalMemberRepository implements MemberRepository {
@Override
public void save(String member) {
System.out.println("원래 구현체");
}
}
// OriginMemberRepository -> NewMemberRepository 변경
@Service
public class MemberService {
private MemberRepository memberRepository; // 코드 변경 없음
public void setMemberRepository(MemberRepository memberRepository) { // 코드 변경 없음
this.memberRepository = memberRepository;
}
}
public interface MemberRepository {
void save(String member);
}
@Repository
public class OriginalMemberRepository implements MemberRepository {
@Override
public void save(String member) {
System.out.println("원래 구현체");
}
}
@Repository
@Primary
public class NewMemberRepository implements MemberRepository {
@Override
public void save(String member) {
System.out.println("새로운 구현체");
}
}
0
안녕하세요, 인프런 AI 인턴입니다. 박도현님.
OCP(Open-Closed Principle) 원칙은 “확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 한다”는 의미로, 코드의 확장 가능성을 열어두면서 기존 코드를 변경하지 않는 방법을 강조합니다.
질문하신 내용은 의존성을 주입(DI, Dependency Injection)하여 클라이언트 코드에서 직접 구현 클래스를 할당하지 않도록 변경하는 방식입니다. setMemberRepository(m)
처럼 외부에서 의존성을 주입하여 Client Code(예: MemberService) 내부를 변경하지 않고도 MemberRepository의 구현체를 바꿀 수 있게 됩니다. 이 과정에서 MemberService의 의존성을 외부로 넘기면서, 클라이언트 코드가 직접적으로 의존하는 것을 줄이게 됩니다.
즉, 문의해주신 방식으로 외부에서 구현 클래스를 주입할 경우, 구현 클래스를 변경하기 위해 클라이언트의 내부 코드를 수정할 필요가 없어지는 이점이 있습니다. 이로 인해, 이 방식은 OCP를 지키는 것에 적합하다고 할 수 있습니다.
이를 통해 구현체의 변경이나 추가가 필요한 경우에도 기존 클라이언트 코드는 변경되지 않기 때문입니다. 이는 코드의 유연성과 확장성을 보장하는 방법 중 하나입니다.
다음 링크는 유사한 주제를 다룬 질문입니다. 도움이 되실 수 있도록 참조해 보세요:
- 의존관계, 레퍼런스, DIP
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
스프링 프레임워크 없이는 의존성을 주입하여 OCP 원칙을 지키는 것이 어렵기 때문에 스프링 프레임워크가 탄생했다는 설명을 해주셨는데,
setMemberRepository(m)와 같은 간단한 메서드만으로 외부에서 쉽게 클라이언트 객체에 넣어줄 수 있다는 생각이 들어서 설명이 잘 와닿지 않습니다. 추가 설명해주시면 감사하겠습니다.
좋은 답변 감사합니다.