로버트 마틴이 좋은 객체지향설계의 5가지 원칙을 정리해놓은 것이다.
단일 책임 원칙(single responsibility principle).
하나의 클래스는 하나의 책임만 가져야 한다. 하나의 책임이라는 것은 모호하다. 클 수도 있고 작을 수도 있고, 상황에 따라서 다를 수도 있다.
중요한 기준은 변경이다. 변경이 있을 때, 어느 한 클래스만 고치면 될 정도라면 단일 책임 원칙을 잘 따른 것이다.
개방-폐쇄 원칙(Open-Closed Principle).
소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야한다.
인터페이스를 만들고 이를 구현하는 클래스들을 여러개 만들어서 여러 버전을 만들 수 있음(다형성 이용).
하지만 순수한 자바 코드로는 OCP를 지킬 수 없는 상황이 발생한다.
리스코프 치환 원칙(Liskov Substitution principle).
프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야 한다.
단순히 컴파일이 되는지의 수준이 아니라, 예를 들어 자동차라는 인터페이스가 있고, '엑셀'이라는 메소드가 있다면, 그 하위 구현체들은 모두 그 '엑셀'을 앞으로 가는 기능으로 구현해야한다. 뒤로가도록 구현한다면 LSP 위반이다.
인터페이스 분리 원칙(Interface Segregation Principle).
특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
인터페이스가 명확해지고 대체 가능성이 높아지는 설계
의존관계 역전 원칙(Dependency Inversion Principle).
프로그래머는 추상화에 의존해야지, 구체화에 의존하면 안된다.
즉 구현체(클래스)에 의존하지 말고 역할(인터페이스)에 의존하라는 것이다. 인터페이스에 의존해야 유연하게 구현체를 변경할 수 있다.
ex) 서비스 클래스에서
MemberRepository m = new MemoryMemberRepository();
이렇게 작성되어있다면 DIP 위반.
서비스 클래스는 인터페이스에만 의존해야한다.
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
DIP가 잘 지켜진 코드.
객체지향의 핵심은 다형성이다. 하지만 다형성만으로는 구현 객체를 변경할 때 클라이언트 코드도 함께 변경해야하는 일이 생긴다.
즉 다형성만으로는 OCP, DIP를 지킬 수가 없는 것이다.
스프링이 OCP, DIP도 지킬 수 있도록 도와줄 수 있다.
자바 코드를 설계할 때, 모든 인터페이스(역할)와 클래스(구현)을 분리하자.
하지만 이렇게 설계하는 것에 장점만 있는 것은 아니다. 그 구현체의 세부 기능을 보려면 클래스를 코드를 보러 들어가야 함. (추상화 비용 발생)
따라서 현실적으로는 기능을 확장할 가능성이 없다면 구체 클래스를 직접 사용하고 향후에 꼭 필요할 때 리펙토링해서 인터페이스를 만드는 것도 방법이다.