![[워밍업 클럽 4기 - 백엔드] Day 4 미션](https://cdn.inflearn.com/public/files/blogs/37bf6908-7df5-4c1d-827d-fb06a860ea91/image (7).png)
[워밍업 클럽 4기 - 백엔드] Day 4 미션
미션
아래 코드와 설명을 보고, [섹션 3. 논리, 사고의 흐름]에서 이야기하는 내용을 중심으로 읽기 좋은 코드로 리팩토링해 봅시다.
[as-is]
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;
}
[to-be]
public class Day4 {
public boolean validateOrder(Order order) {
try {
isOrderItemsEmpty(order);
isCustomerInfoEmpty(order);
isTotalPricePositive(order);
System.out.println("유효성 검사를 통과했습니다.");
return true;
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
return false;
}
}
private static void isCustomerInfoEmpty(Order order) {
if(!order.hasCustomerInfo()) {
throw new IllegalArgumentException("사용자 정보가 없습니다.");
}
}
private static void isTotalPricePositive(Order order) {
if(order.getTotalPrice() < 0) {
throw new IllegalArgumentException("올바르지 않은 총 가격입니다.");
}
}
private static void isOrderItemsEmpty(Order order) {
if(order.getItems().isEmpty()) {
throw new IllegalArgumentException("주문 항목이 없습니다.");
}
}
}
class Order {
private final List<Item> orderItem = new ArrayList<>();
private Customer customer;
public void setItem(Item item) {
orderItem.add(item);
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public List<Item> getItems() {
return orderItem;
}
public int getTotalPrice() {
int totalPrice = 0;
for(Item item : orderItem) {
totalPrice += item.getPrice();
}
return totalPrice;
}
public boolean hasCustomerInfo() {
return customer != null;
}
}
class Customer {
private String id;
public Customer(String id) {
this.id = id;
}
}
class Item {
private final int price;
public Item(int price) {
this.price = price;
}
public int getPrice() {
return price;
}
}
수업에서 배운 내용들을 차분히 적용하도록 노력했다. 다음과 같은 순서로 리팩토링을 진행했다.
메인인 validateOrder() 메서드 외엔 추상화를 적용하지 못했다. (시간이 없..어서)
Early return
복잡하게 얽혀있던 if-else문을 뜯어내 if문을 최소화했다.메서드 추상화
메서드의 경우엔 이름이 정말 고민 많았는데, 일단 세 메서드 다 isXXX로 통일시켰다.예외처리
예외 처리를 통해 유효성 검사가 통과되지 않았을 때의 로직을 통일했다. return false를 하나하나 써주지 않아도 됐다.
테스트 결과
public void run() {
System.out.println("======= 시작 =======");
Order order1 = new Order();
validateOrder(order1); // "주문 항목이 없습니다."
Order order2 = new Order();
Item item = new Item(1000);
order2.setItem(item);
validateOrder(order2); // "사용자 정보가 없습니다."
Order order3 = new Order();
Item item2 = new Item(-10);
order3.setCustomer(new Customer("id3"));
order3.setItem(item2);
validateOrder(order3);// "올바르지 않은 총 가격입니다."
Order order4 = new Order();
Item item4 = new Item(1000);
order4.setCustomer(new Customer("id4"));
order4.setItem(item4);
validateOrder(order4); // "유효성 검사를 통과했습니다."
}
SOLID에 대하여 자기만의 언어로 정리해 봅시다.
SRP : Single Responsibility Principle / 단일 책임 원칙
이상적인 사회 모습. 회사에서 한 사람 당 하나의 책임만 가졌으면 좋겠는 것 처럼, 객체는 단 하나의 책임만 가져야 한다. 하나의 객체가 여러 책임을 가질 경우 변경 시 파급력이 크다.
OCP : Open-Closed Principle / 개방-폐쇄 원칙
열린교회 닫힘. 새 신도는 환영하면서 문을 열어주지만 나갈때는 아니란다. 소프트웨어 요소는 확장에는 열려있어야 하고 변경에는 닫혀있어야 한다. 추가적인 요구사항에 유연하게 확장할 수 있어야한다. 기능 추가 시 최소한의 코드를 수정해야 함(물론 로직에 직접적인 영향을 주는 코드는 수정 X)
LSP : Liskov Substitution Principle / 리스코프 치환 원칙
자식은 부모의 거울이다! 자식 클래스는 부모 클래스의 기능을 정확하게 확장해야한다.
ISP : Interface Segregation Principle / 인터페이스 분리 원칙
객체와 똑같다. 하나의 인터페이스에 너무 많은 기능을 넣으면 원치않는 의존성이 생길 수 있다.
DIP : Dependency Inversion Principle / 의존 역전 원칙
구현체가 아닌 추상에 의존해야 한다. 구현체에 의존하게 되면 어떠한 인터페이스에 대한 구현체가 바뀔 때마다 다른 코드에 영향을 줄 수 있다 !! 결합도를 낮추고 유연한 구조를 만든다.
출처
댓글을 작성해보세요.