SRP(Single Responsibility Principle) : 단일 책임 원칙
OCP(Open Closed Principle) : 개방 폐쇄 원칙
LSP(Liskov Substitution Principle) : 리스코프 치환 원칙
ISP(Interface Segregation Principle) : 인터페이스 분리 원칙
DIP(Dependency Inversion Principle) : 의존 역전 원칙
"어떤 클래스를 변경해야 하는 이유는 오직 하나뿐이어야 한다"
단일 책임 원칙이란 하나의 클래스가 여러가지의 역할(책임)을 가지지 말고 분리하여 관리하라는 것이다.
먼저 이러한 규칙을 지키지 못하는 상황을 코드로 보여주도록 하겠다.
class 강아지{
final static Boolean 수컷 = true;
final static Boolean 암컷 = false;
Boolean 성별;
void 소변보다(){
if(this.성별 = 수컷){
// 한쪽 다리를 들고 소변을 본다.
} else {
// 뒷다리 두 개를 굽혀 앉은 자세로 소변을 본다.
}
}
}
위 코드는 하나의 클래스에서 강아지의 암컷, 수컷을 동시에 처리하려고 한 코드이다. 이렇게 if문을 사용하여 처리하는 것은 단일 책임 원칙(SRP)에 맞지 않다.
그렇다면 어떻게 코드를 처리하는 것이 옳게 된 방식일까?
바로 보여주겠다.
abstract class 강아지{
abstract void 소변보다()
}
class 수컷강아지 extends 강아지{
void 소변보다() {
//한쪽 다리를 들고 소변을 본다.
}
}
class 암컷강아지 extends 강아지{
void 소변보다() {
//뒷다리 두 개로 앉은 자세로 소변을 본다.
}
}
이렇게 한 클래스가 두 개를 담당하는 것이 아닌 따로 나누는 것이 원칙을 준수한 코딩이라고 볼 수 있다.
"소프트웨어 엔티티(클래스,모듈,함수 등)는 확장에 대해서는 열려 있어야 하지만 변경에 대해서는 닫혀 있어야 한다."
개방 폐쇄 원칙은 어떠한 애플리케이션에 대한 기능은 확장할 수 있지만 기존에 대한 코드는 변경하지 말아야한다는 뜻이다.
개방 폐쇄 원칙에 대한 예시를 들자면 손님이 물건을 사는 과정에서 있다.
손님이 물건을 구매할 때 어떤 직원이 계산을 해주어도 문제가 일어나지 않는다는 것에서 직원 교대라고 하는 주변의 변화에 손님의 구매 행위는 영향을 받지 않는 것이고, 직원은 교대라고 하는 확장 행위에는 열려 있는 것이다.
결국 그림과 같이 상위 클래스 또는 인터페이스를 중간에 둠으로써 변화가 생기더라도 손님은 피해가 가지 않게 되는 것이다.
"서브 타입은 언제나 자신의 기반 타입으로 교체할 수 있어야 한다"
리스코프 치환 원칙은 간단하다. 바로 "하위 클래스의 인스턴스는 상위형 객체 참조 변수에 대입해 상위 클래스의 인스턴스 역할을 하는데 문제가 없어야 한다는 것"이다.
그림을 예로 들어보겠다.
위 그림에서 박쥐는 포유류이다. 또한 박쥐는 동물이다. 이처럼 상위 클래스의 인스턴스 역할을 해주어야 한다는 것이다.
동물 박쥐 = new 포유류() //가 성립
"클라이언트는 자신이 사용하지 않는 메서드에 의존관계를 맺으면 안된다"
ISP는 위에서 설명했었던 SRP의 새로운 해결 방식이다. SRP에서는 새로운 클래스로 정의를 하였다면 ISP는 클래서 하나에서 인터페이스를 분할해 처리를 하는 방식이다.
인터페이스 분할 원칙을 이야기할 때 항상 함께 등장하는 원칙 중 하나로 인터페이스 최수주의 원칙이 있다. 인터페이스를 통해 메서드를 외부에 제공할 때는 최소한의 메서드만 제공하라는 것이다.
만약 ISP방식을 사용하려면 밑의 내용을 기억하는 것이 좋다.
"상위 클래스는 풍성할수록 좋고, 인터페이스는 작을수록 좋다"
"고차원 모듈은 저차원 모듈에 의존하면 안 된다. 이 두 모듈 모두 다른 추상화 된 것에 의존해야 한다"
"추상화된 것은 구체적인 것에 의존하면 안된다. 구체적인 것이 추상화된 것에 의존해야한다"
"자주 변경되는 구체 클래스에 의존하지 마라"
간단한 예시를 그림으로 보여주겠다.
위 그림은 의존 역전 원칙이 적용이 되지 않은 모습이다. 만약 스노우타이어가 바뀌게 된다면 그에 대한 대책이 없기 때문에 고차원 모듈이 저차원 모듈에 의존을 하게 되는 것이기 때문이다.
그렇다면 어떻게 설계를 하는 것이 바람직한지 보여주겠다.
이와 같이 자동차가 구체적인 타이어들이 아닌 추상화된 타이어 인터페이스에만 의존하게 함으로써 변경이 되도 자동차에는 영향이 안가게 설정을 하였다.
참조-스프링 입문을 위한 자바 객체 지향의 원리와 이해