클린코드 저자 로버트 마틴이 좋은 객체 지향 설계의 5가지 원칙을 정리
SRP 단일 책임 원칙 : Single Responsibility Principle
⭐ OCP 개방 폐쇄 원칙 : Opne/Closed Principle 🤨
public class MemeberService {
// MemberRepository m = new MemoryMemberRepository(); // 기존코드
MemberRepository m = new JdbcMemberRepository(); // 변경코드
}
구현 객체를 변경하려면 클라이언트 코드를 변경해야 한다… !
다형성은 사용했지만, OCP 원칙을 지킬 수 없다.
= 다시 MemoryMemberRepository로 변경하고 싶다면 MemberService클래스 코드의 변경이 필요하다.
= MemberService 클라이언트가 구현 클래스를 직접 선택하기 때문에, 구현 객체를 변경하려면 클라이언트 코드를 변경해야 한다.
⭐ 해결방법
객체를 생성하고, 연관관계를 맺어주는 별도의 조합, 설정자가 필요하다.
이걸 스프링 컨테이너가 해준다 !
LSP 리스코프 치환 원칙 : Liskov substitution principle
프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야한다.
ISP 인터페이스 분리 원칙 : Interface segregation principle
⭐ DIP 의존 관계 역전 : Dependency inversion principle
추상화에 의존해야지, 구체화에 의존하면 안된다. = 의존성 주입
→ 구현 클래스에 의존하지 말고, 인터페이스에 의존하다.
→ 클라이언트는 인터페이스만 바라보면 된다.
→ 역할(Role)에 의존해야한다.
왜? 클라이언트가 인터페이스에 의존해야 유연하게 구현체를 변경할 수 있다. 구현체에 의존하면 변경이 어려워진다.
// MemberService클래스는 MemberRepository를 필드로 가지면서,
// new로 MemoryMemberRepostiory를 할당
// -> 인터페이스에 의존하지만 동시에 구현체에도 의존하고 있다. **-> DIP 위반**
// 의존한다는 것 = 안다. MemberService가 MemberRepostiory(인터페이스)뿐만 아니라, MemoryMemberRepostiory(구현 클래스)도 알고 있다
// MemberService 클라이언트가 구현 클래스를 직접 선택하고 있는 것이다.
public class MemeberService {
MemberRepository m = new MemoryMemberRepository(); // 기존코드
MemberRepository m = new JdbcMemberRepository(); // 변경코드
}
해결 방법
객체 지향의 핵심은 다형성
이지만, 다형성 만으로는 부족하다.
다형성만으로는 구현 객체를 변경할 때 클라이언트 코드(MemberService
)도 함께 변경해야하고,
이는 OCP(개방 폐쇄 원칙), DIP(의존 관계 역전)를 지키지 못 하는 것이다.
→ 무언가가 더 필요하다 !
📌 다형성(polymorphism)이란?
부모-자식 상속 관계에 있는 클래스에서상위 클래스가 동일한 메시지로 하위 클래스들을 서로 다르게 동작시키는 객체 지향 원리이다.