[워밍업 클럽 4기 - 백엔드] Day 4 미션

[워밍업 클럽 4기 - 백엔드] Day 4 미션

미션

  1. 아래 코드와 설명을 보고, [섹션 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() 메서드 외엔 추상화를 적용하지 못했다. (시간이 없..어서)

 

  1. Early return
    복잡하게 얽혀있던 if-else문을 뜯어내 if문을 최소화했다.

     

  2. 메서드 추상화


    메서드의 경우엔 이름이 정말 고민 많았는데, 일단 세 메서드 다 isXXX로 통일시켰다.

  3. 예외처리


    예외 처리를 통해 유효성 검사가 통과되지 않았을 때의 로직을 통일했다. 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); // "유효성 검사를 통과했습니다."
}

image

 

  1. SOLID에 대하여 자기만의 언어로 정리해 봅시다.

  • SRP : Single Responsibility Principle / 단일 책임 원칙

    • 이상적인 사회 모습. 회사에서 한 사람 당 하나의 책임만 가졌으면 좋겠는 것 처럼, 객체는 단 하나의 책임만 가져야 한다. 하나의 객체가 여러 책임을 가질 경우 변경 시 파급력이 크다.

     

  • OCP : Open-Closed Principle / 개방-폐쇄 원칙

    • 열린교회 닫힘. 새 신도는 환영하면서 문을 열어주지만 나갈때는 아니란다. 소프트웨어 요소는 확장에는 열려있어야 하고 변경에는 닫혀있어야 한다. 추가적인 요구사항에 유연하게 확장할 수 있어야한다. 기능 추가 시 최소한의 코드를 수정해야 함(물론 로직에 직접적인 영향을 주는 코드는 수정 X)

       

     

  • LSP : Liskov Substitution Principle / 리스코프 치환 원칙

    • 자식은 부모의 거울이다! 자식 클래스는 부모 클래스의 기능을 정확하게 확장해야한다.

     

  • ISP : Interface Segregation Principle / 인터페이스 분리 원칙

    • 객체와 똑같다. 하나의 인터페이스에 너무 많은 기능을 넣으면 원치않는 의존성이 생길 수 있다.

     

  • DIP : Dependency Inversion Principle / 의존 역전 원칙

    • 구현체가 아닌 추상에 의존해야 한다. 구현체에 의존하게 되면 어떠한 인터페이스에 대한 구현체가 바뀔 때마다 다른 코드에 영향을 줄 수 있다 !! 결합도를 낮추고 유연한 구조를 만든다.

       

 

출처

댓글을 작성해보세요.

채널톡 아이콘