미션 설명
1. 아래 코드와 설명을 보고, [섹션 3. 논리, 사고의 흐름]에서 이야기하는 내용을 중심으로 읽기 좋은 코드로 리팩토링해 봅시다.
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;
}
2. SOLID에 대하여 자기만의 언어로 정리해 봅시다.
나의 답
첫번째 문항
public static final String NO_ORDER_ITEM = "주문 항목이 없습니다.";
public static final String INVALID_TOTAL_PRICE = "올바르지 않은 총 가격입니다.";
public static final String NO_USER_INFO = "사용자 정보가 없습니다.";
public boolean validateOrder(Order order) throws OrderException {
if (order.doesHaveItem()) {
throw new OrderException(NO_ORDER_ITEM);
}
if (order.doesNotHaveValidTotalPrice()) {
throw new OrderException(INVALID_TOTAL_PRICE);
}
if (order.doesNotHaveCustomerInfo()) {
throw new OrderException(NO_USER_INFO);
}
return true;
}
Order
public abstract class Order {
public abstract boolean doesHaveItem();
public abstract boolean doesNotHaveValidTotalPrice();
public abstract boolean doesNotHaveCustomerInfo();
}
변경 사항
- if문의 조건들을 하나의 함수로 정의함으로써 조건의 의미를 명확히 했습니다.
- if문의 조건에 부합하지 않을 경우 바로 결과를 반환하게 했습니다.
- 불필요한 부정 조건을 제거했습니다.
- 별개의 예외 처리 클래스를 생성하여 예외를 명확히 했습니다.
- 관심사를 기준으로 공백을 두었습니다.
두번째 문항
- S
- SRP (단일 책임 원칙)
- 하나의 클래스는 하나의 책임(=관심사)을 가져야 한다.
- SRP를 지킴으로써 객체들을 관심사 기준으로 분리할 수 있다.
- 높은 응집도와 낮은 결합도를 제공한다.
- 응집도
- 클래스나 모듈 내 요소들이 긴밀하게 연관되어있는 정도
- 결합도
- 한 요소가 변경되었을 때 다른 요소들이 영향을 받는 정도
- O
- OCP (개방-폐쇄 원칙)
- 확장에는 열려 있고, 수정에는 닫혀 있어야 한다.
- 기존 코드의 변경 없이도 시스템의 기능을 확장할 수 있어야 한다.
- 추상화와 다형성을 활용함으로써 구현할 수 있다.
- L
- LSP (리스코프 치환 원칙)
- 두 클래스가 상속 구조를 가질 때 부모 클래스의 인스턴스를 자식 클래스로 치환하여도 기능 상에 문제가 없어야 한다.
- 자식 클래스는
- 부모 클래스의 책임을 준수해야 한다.
- 부모 클래스의 행동을 변경하지 않아야 한다.
- LSP를 위반할 경우 아래 문제가 발생할 수 있다.
- 오동작
- 예상 밖의 예외
- 위 두 문제를 방지하기 위한 불필요한 타입 체크 동반
- I
- ISP (인터페이스 분리 원칙)
- 클라이언트는 자신이 사용하지 않은 인터페이스에 의존하면 안된다.
- ISP를 위반할 경우
- 불필요한 의존성으로 인해 결합도가 높아진다.
- 특정 기능의 변경이 여러 클래스에 영향을 미칠 수 있다.
- 필요한 기능 단위로 인터페이스를 나눠서 사용해라.
- D
- DIP (의존성 역전 원칙)
- 상위 수준의 모듈은 하위 수준의 모듈에 직접 의존해서는 안된다.
- 추상화(인터페이스, 추상 클래스)에 의존해야 한다.
- 의존성의 순방향
- 의존성의 역방향
- DIP를 지킬 경우 저수준 모듈의 변경이 고수준 모듈에 영향을 미치지 않게 된다.