⚡ 다시 한 번 강조!
역할과 구현을 철저하게 분리하여 설계해야 한다. 언제든지 갈아끼울 수 있도록!
클린코드로 유명한 로버트 마틴이 좋은 객체 지향 설계의 5가지 원칙을 정리
중요한 기준 : 변경을 했을 때 파급 효과가 적으면 SRP를 잘 따른 것
즉, 변경이 있을 때 하나의 클래스에 하나의 지점만 고치면 잘 따른다고 할 수 있다.
예) UI 변경, 객체의 생성과 사용을 분리
한 클래스는 하나의 책임만 가져야 한다.
하나의 책임이라는 것은 모호하다. 클 수도 있고, 작을 수도 있다. 문맥과 상황에 따라 다르다.
책임이라는 범위를 적절하게 잘 조절하자!
소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.
말이 되나? 확장을 하려면 기능을 추가해야 하는데 코드의 변경 없이 기능 추가가 가능한가?
-> 다형성!! 을 활용하기!
인터페이스를 구현한 새로운 클래스를 하나 만들어서 새로운 기능을 구현
새로운 클래스를 하나 만드는 것은 기존 코드를 변경한다고 할 수 없다. 기존 코드에는 전혀 변경 없이 그냥 새로운 클래스가 하나 만들어지는 것이다.
역할과 구현의 분리
하지만!! 만든 것을 적용할 때 문제가 있다.
클라이언트 : MemberService
서버 : MemberRepository
< MemberService >
클라이언트인 MemberService가 구현 클래스를 직접 선택
public class MemberService {
// private MemberRepository m = new MemoryMemberRepository(); // 기존 코드
private MemberRepository m = new JdbcMemberRepository(); // 변경 코드
}
예) 구현된 자동차 BMW에서 벤츠로 변경하려면 운전자가 구현 자동차를 선택하는 코드를 변경해야 한다.
다형성을 활용해서 기능을 넣기 위해서는 클라이언트가 변경 될 수 밖에 없다.
다시 말해서, 구현 객체를 변경하려면 클라이언트 코드를 변경 해야한다.
!! 분명 다형성을 사용했지만 !! OCP 원칙을 지킬 수 없다.
이것이 스프링 컨테이너의 역할이다.
따라서 이 원칙을 지키기 위해 DI와 IoC 컨테이너 라는 개념이 필요한 것이다.
역할에 의존해야 한다. 구현보다 역할!
프로그래머는 "추상화에 의존해야지, 구체화에 의존하면 안된다."
즉, 구현 클래스에 의존하지 말고 인터페이스에 의존하라는 뜻이다.
객체 세상도 클라이언트가 인터페이스에 의존해야 유연하게 구현체를 변경할 수 있다. 구현체에 의존하게 되면 변경이 아주 어려워진다.
그런데!!
< MemberService >
public class MemberService {
private MemberRepository m = new MemoryMemberRepository();
}
MemberRepository 필드를 가지고 있는데, MemoryMemberRepository를 할당하고 있다.
즉, 두 개 모두 의존하고 있다. -> DIP 위반이다!!
❓ 의존한다?
MemberService는 MemberRepository에만 의존하도록 설계해야 한다.
어떻게?! -> 다음 게시물로!!