[Java] SOLID원칙

acacia·2022년 10월 10일
1

객체지향 설계의 5원칙 : SOLID

단일 책임 원칙: SRP (Single Responsibility Principle)
개방 폐쇄 원칙: OCP (Open Closed Priciple)
리스코프 치환 원칙: LSP (Listov Substitution Priciple)
인터페이스 분리 원칙: ISP (Interface Segregation Principle)
의존 역전 원칙: DIP (Dependency Inversion Principle)

1. SRP

- 단일 책임 원칙

어떤 클래스를 변경해야 하는 이유는 오직 하나뿐이어야 한다.
-로버트 C.마틴


다음 그림과 같은 클래스가 있다고 가정해볼때, 이 남자의 역할과 책임이 많은 것을 확인 할 수 있다.
예를 들어, 어느 날, 여자친구와 헤어졌다면 기념일 챙기기 및 키스하기가 어렵다.
거기에 여자친구 없는 스트레스가 주변 사람에게도 영향을 미치게 될 것이다.

이런 경우 역할 (책임)을 분리하는 것이 필요하다.


메소드가 단일 책임을 지키지 않은 경우

class 강아지 {
    final static Boolean 수컷 = true;
    final static Boolean 암컷 = false;
    Boolean 성별;

    void 소변보다() {
        if (this.성별 == 수컷) {
            // 한쪽 다리를 들고 소변을 보다.
        } else {
            // 뒷다리 두 개를 굽혀 앉은 자세로 소변을 본다.
        }
    }   
}

강아지 클래스 소변보다()가 수컷, 암컷 강아지의 행위를 모두 구현하기 위해 분기 처리를 위한 if문의 사용으로 단일 책임(행위) 원칙을 위배하고 있다.

메소드에 단일 책임 원칙을 적용한 경우

abstract class 강아지 {
    abstract void 소변보다();
}

class 수컷강아지 extends 강아지 {
    void 소변보다() {
        // 한쪽 다리를 들고 소변을 본다.
    }
}

class 암컷강아지 extends 강아지 {
    void 소변보다() {
        // 뒷다리 두 개로 앉은 자세로 소변을 본다.
    }
}

추상 클래스 강아지를 두고 수컷강아지, 암컷강아지 클래스가 각자 자신의 특징에 맞게 소변보다() 메소드를 구현해 단일 책임 원칙을 적용했다.



2. OCP

- 개방 폐쇄 원칙

소프트웨어 엔티티(클래스, 모듈, 함수 등)는 확장에 대해서는 열려 있어야 하지만 변경에 대해서는 닫혀 있어야한다
-로버트 C.마틴

위 문장을 조금 더 의역해보자면?

"자신의 확장에는 열려 있고, 주변의 변화에 대해서는 닫혀 있어야 한다"

위 그림에서 운전자는 기어가 수동 or 자동이냐에 따라 행동이 달라진다.
어떤 변화가 운전자에게 영향을 미치고 있어 개방 폐쇄 원칙에 위배된다는 것이다.

그림과 같이 상위 클래스 또는 인터페이스를 중간에 둠으로써 다양한 자동차가 생긴다 해도 객체 지향 세계의 운전자는 운전 습관에 영향을 받지 않게 된다.

즉,

다양한 자동차가 생긴다는 것은 자동차 입장에서 자신의 확장에는 개방되어 있는 것이고, 운전자 입장에서는 주변의 변화에 폐쇄돼 있는 것이다.

데이터베이스의 개방 폐쇄 원칙의 아주 좋은 예

JDBC는 개방 폐쇄 원칙의 가장 좋은 예이다.
데이터베이스가 MySQL에서 오라클로 바뀌더라도 Connection을 설정하는 부분만 변경해주면 된다.

자바 애플리케이션은 데이터베이스라고 하는 주변의 변화에 닫혀 있는 것이고, 데이터베이스를 교체한다는 것은 데이터베이스가 자신의 확장에는 열려 있다는 것 이다.



3. LSP

- 리스코프 치환 원칙

서브 타입은 언제나 자신의 기반 타입(base type)으로 교체할 수 있어야 한다
-로버트 C.마틴

* 하위 클래스 is a kind of 상위 클래스
>  하위 분류는 상위 분류의 한 종류다. 
* 구현 클래스 is able to 인터페이스
> 구현 분류는 인터페이스할 수 있어야 한다.

위 두개의 문장대로 구현된 프로그램이라면 이미 리스코프 치환 원칙을 잘 지키고 있다.


리스코프 치환 원칙 위반 사례
계층도 / 조직도

딸이 아버지, 할아버지 역할을 하는 것이 논리에 맞지 않는다.


리스코프 치환 원칙 적용 사례

분류도


하위의 것들이 상위 것들의 역할을 하는 데 전혀 문제가 없다.

  • 리스코프 치환 원칙은 객체 지향의 상속이라는 특성을 올바르게 활용하면 자연스럽게 얻어지는 것이다.



ISP

- 인터페이스 분리 원칙

클라이언트는 자신이 사용하지 않는 메서드에 의존 관계를 맺으면 안된다.
-로버트 C.마틴

SRP에서는 남자 클래스를 분리해 하나의 역할(책임)만 하는 다수의 클래스로 분할한다.

하지만, ISP에서는 각 역할에 맞게 인터페이스로 분리하여 사용할 수 있다.

(ex 어머니한테는 아들, 여자친구한테는 남자친구)

결론적으로는 단일 책임 원칙(SRP)과 인터페이스 분할 원칙(ISP)은 같은 문제에 대한 두 가지 다른 해결책이라고 볼 수 있다.

하지만 특별한 경우가 아니라면 단일 책임 원칙을 적용하는 것이 더 좋은 해결책이라고 할 수 있다.

인터페이스 최소주의 원칙

인터페이스 내에 메소드는 최소한 일수록 좋다.



DIP

- 의존 역전 원칙

고차원 모듈은 저차원 모듈에 의존하면 안 된다. 이 두 모듈 모두 다른 추상화된 것에 의존해야 한다. 추상화된 것은 구체적인 것에 의존하면 안 된다. 구체적인 것이 추상화된 것에 의존해야 한다.자주 변경되는 구체(Concrete) 클래스에 의존하지 마라
-로버트 C.마틴

의존 역전 원칙 적용 전

자주 변경되는 구체 클래스에 의존하는 경우

자동차가 타이어에 의존하면?
자동차 타이어는 자주 바뀌게 되는 것 중 하나로, 이렇게 자주 바뀌는 것에 의존하면 자동차는 영향을 받게 되어 있다.


의존 역전 원칙 적용 후

자동차가 구체적인 타이어가 아닌 추상화된 타이어 인터페이스에만 의존하게 함으로써 타이어가 변경되어도 자동차가 영향을 받지 않는다.


자신보다 변하기 쉬운 것에 의존하던 것추상화된 인터페이스상위 클래스를 두어 변하기 쉬운 것의 변화에 영향받지 않게 하는 것이 DIP 의존 역전 원칙이다.


📚 Reference

스프링 입문을 위한 자바 객체지향의 원리와 이해

profile
게으른 개발자의 부지런한 개발일지

0개의 댓글