SOLID를 나만의 언어로 표현해보자! - 인프런 워밍업 클럽 2기

이재훈·2024년 10월 3일
0

JAVA8

목록 보기
23/23

SOLID가 뭔데 ?

객체 지향 설계 5원칙이다.

  • SRP : 단일 책임 원칙
  • OCP : 개방 폐쇄 원칙
  • LSP : 리스코프 치환 원칙
  • ISP : 인터페이스 분리 원칙
  • DIP : 의존 역전 원칙

정말 정말 쉽게 이 5원칙을 설명하자면 유지보수 하기 쉽고, 추가 기능 개발 요청이 왔을 때 최대한 개발 시간을 줄이고 사이드 이펙트를 줄일 수 있게 하는 꿀팁의 모음이라고 생각을 한다.

SRP - 단일 책임 원칙

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

하나의 클래스는 하나의 책임을 가져야 한다. 예를 들어 학교에 선생님을 클래스로 표현해보겠다. (정말 간단하게)

public class Teacher {
    private String name; // 이름
    private String subject; // 과목
}

근데 이 선생님이 퇴근 후에 은행에 가게 되었다. 그러면 이 클래스는 아래와 같이 변한다.

public class Teacher {
    private String name;
    private String subject;
    private Money money;
    private String residentRegistrationNumber;
}

자 이제 이 클래스는 두가지의 역할을 가지게 되었다. 선생님과 은행 고객 두 가지이다.

이제 은행에서 은행 고객에게 추가로 어떤 정보를 요청할 때도 해당 클래스가 변경되고, 선생님에게 새로운 룰이 추가가 되어도 해당 클래스가 변경이 된다. 이럴 때는 Teacher class 와 BankCustomer class를 분리하자!!

public class Teacher {
    private String name;
    private String subject;
}
public class Teacher {
    private String name;
    private Money money;
    private String residentRegistrationNumber;
}

OCP : 개방 폐쇄 원칙

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

자신의 확장에는 열려 있고, 주변의 변화에는 닫혀 있어야 한다.
자동차의 타이어를 예로 들 수 있다. 자동차 타이어 회사는 몇 개가 있을까?

간단하게 검색만 해도 이렇게 많이 나온다. 만약 타이어 인터페이스가 없다면 ? 차를 클래스로 표현해 보겠다.

public class Car {
    private String name;
    private KumhoTire tire; // 금호 타이어
}

타이어를 잘 사용하다가 다른 회사의 타이어를 사용하고 싶다면 ??
차 클래스의 코드가 변경 되어야 한다. 이것은 OCP를 위반한다.

public class Car {
    private String name;
    private KoreanTire tire;
}

어떻게 해결해야 할까? Car 클래스가 바퀴를 인터페이스로 받으면 해결된다.

public class Car {
    private String name;
    private Tire tire;
}

이제 Car 클래스는 타이어가 바뀌더라도 변경되지 않는다. OCP를 지키게 된 것이다.

LSP : 리스코프 치환 원칙

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

객체 지향의 상속 조건

  • 하위 클래스 is kind of 상위 클래스 - 하위 분류는 상위 분류의 한 종류이다.
  • 구현 클래스 is able to 인터페이스 - 구현 분류는 인터페이스 할 수 있어야 한다.
    위 두 개의 문장대로 구현된 프로그램이라면 이미 LSP를 잘 지키고 있는 것이다.

쉽게 말하면 아래와 같다.

  • 자식은 부모의 종류 중 하나이다 -> (X)
  • 고래는 포유류의 종류 중 하나이다. -> (O)

부모 클래스와 자식 클래스라고 불리는 것은 잘못된 말이다.
자식이 부모의 역할을 할 수 있어야 하는데 그건 아닌 것 같다..

결국 리스코프 치환 원칙은 객체 지향에서 상속이라는 특성을 올바르게 활용한다면 자연스럽게 얻게 되는 것이다.

ISP : 인터페이스 분리 원칙

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

쉽게 얘기를 하자면 클래스가 인터페이스를 구현할 때 필요 없는 메서드까지 구현해야 한다면 그것은 ISP를 위반한 것이다. 그럴 때는 인터페이스를 분리하자 !! ISP는 인터페이스의 단일 책임 원칙을 강조한다.
SRP와 ISP를 동시에 만족하지 못할 상황이 발생하기도 한다.

그럴 때는 상황에 맞춰서 결정하도록 하자!

DIP : 의존 역전 원칙

  • 고차원 모듈은 저차원 모듈에 의존하면 안된다. 이 두 모듈은 다른 추상화된 것에 의존해야 한다.
  • 추상화 된 것은 구체적인 것에 의존하면 안된다. 구체적인 것이 추상화된 것에 의존해야 한다.

"자주 변경되는 클래스에 의존하지 마라. - 로버트 C.마틴"

OCP에 작성했던 예시와 같게 들 수 있다.

Car는 Tire가 자주 변경된다면 Car는 Tire를 의존하면 안된다. 이 때 DIP를 적용하여 타이어 인터페이스에 의존하게 하여 결합도를 낮출 수 있고, DIP를 지킬 수 있다.

워밍업 day4 미션

아래 코드를 리팩토링 해보시오

public boolean validateOrder(Order order) {
    if (order.getItems().size() == 0) {
        log.info("주문 항목이 없습니다.");
        return false;
    } else {
        if (order.getTotalPrice() > 0) {
            if (!order.hasCustomerInfo()) {
                log.info("사용자 정보가 없습니다.");
                return false;
            } else {
                return true;
            }
        } else if (!(order.getTotalPrice() > 0)) {
            log.info("올바르지 않은 총 가격입니다.");
            return false;
        }
    }
    return true;
}

나는 아래와 같이 코드를 리팩토링 해보았다.

public void validateOrder(Order order) {
    
    if (order.hasNotCustomerInfo()) {
        throw new IllegalArgumentException("사용자 정보가 없습니다.");
    }
    
    if (order.isNoItem()) {
        throw new IllegalArgumentException("주문 항목이 없습니다.");
    }

    if (order.isTotalPriceisNegative()) {
        throw new IllegalArgumentException("올바르지 않은 총 가격입니다.");
    }
}

validateOrder는 boolean을 굳이 반환이 필요 없다고 생각한다. void로 바꾼 후 문제가 있을 시 익셉션을 던지게 하였다. 또한 order의 상태를 order에게 직접 물어봄으로써 좀 더 가독성이 좋고, 응집도 높은 코드로 변경 하였다.

많은 개발자들이 객체 지향 언어라고 불리는 Java를 사용하지만 내가 정말 객체 지향적으로 잘 사용하고 있냐는 질문에 '예' 라고 대답할 수 있는 개발자는 흔하지 않을 것이라고 생각한다. 나 또한 객체 지향 언어를 제대로 활용하고 있다고 말하지 못한다. 객체 지향 언어를 사용하면서 객체 지향 설계를 못한다는 것은 많이 아쉬운 부분이라고 생각해서, 이번에 인프런 워밍업 클럽 2기 (백엔드 클린 코드, 테스트코드)에 참여하게 되었다.

profile
부족함을 인정하고 노력하자

0개의 댓글