워밍업 클럽 4기 - 백엔드 Day 4 [객체 지향 패러다임]
18일 전
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 Item {
private String name;
private int quantity;
private int unitPrice;
public Item(String name, int quantity, int unitPrice) {
this.name = name;
this.quantity = quantity;
this.unitPrice = unitPrice;
}
public int getQuantity() {
return quantity;
}
public int getSubtotal() {
return quantity * unitPrice;
}
}
public class Order {
private List<Item> items;
private Customer customer;
public Order(List<Item> items, Customer customer) {
this.items = items;
this.customer = customer;
}
public int getTotalItemCount() {
return items.stream()
.mapToInt(Item::getQuantity)
.sum();
}
public int getTotalPrice() {
return items.stream()
.mapToInt(Item::getSubtotal)
.sum();
}
public boolean isCustomerInfoEmpty() {
return customer == null || customer.isEmpty();
}
}
public class Customer {
private String name;
private String email;
public Customer(String name, String email) {
this.name = name;
this.email = email;
}
public boolean isEmpty() {
return (name == null || name.isBlank()) &&
(email == null || email.isBlank());
}
}
public class OrderValidator {
public void isValid(Order order) {
if (isEmpty(order)) {
System.out.println("주문 항목이 없습니다.");
return;
}
if (isPriceInvalid(order)) {
System.out.println("올바르지 않은 총 가격입니다.");
return;
}
if (isMissingCustomerInfo(order)) {
System.out.println("사용자 정보가 없습니다.");
return;
}
System.out.println("유효성 검사를 통과했습니다.");
}
private boolean isEmpty(Order order) {
return order.getTotalItemCount() == 0;
}
private boolean isPriceInvalid(Order order) {
return order.getTotalPrice() <= 0;
}
private boolean isMissingCustomerInfo(Order order) {
return order.isCustomerInfoEmpty();
}
}
테스트
public class AppRunner {
public static void main(String[] args) {
OrderValidator validator = new OrderValidator();
System.out.println("======= 주문 유효성 테스트 시작 =======");
Order emptyOrder = new Order(Collections.emptyList(), null);
validator.isValid(emptyOrder);
List<Item> items1 = List.of(
new Item("노트북", 1, 1000000)
);
Order noCustomerOrder = new Order(items1, null);
validator.isValid(noCustomerOrder);
List<Item> items2 = List.of(
new Item("샤프", 1, -100)
);
Customer customer1 = new Customer("홍길동", "hong@example.com");
Order negativePriceOrder = new Order(items2, customer1);
validator.isValid(negativePriceOrder);
List<Item> items3 = List.of(
new Item("모니터", 2, 150000)
);
Customer customer2 = new Customer("김철수", "kim@example.com");
Order validOrder = new Order(items3, customer2);
validator.isValid(validOrder);
System.out.println("======= 테스트 종료 =======");
}
}
2. SOLID에 대하여 자기만의 언어로 정리해 봅시다.
SRP
하나의 트레이에 하나의 물건을 담아야 정리하기 편하다.
-> 클래스도 하나의 책임만 가져야 유지보수 편리
OCP
멀티탭에 새 기기 꽂는 것은 쉬운 데에 반해, 멀티탭 자체를 고치는 것은 힘들다.
-> 기존 코드를 고치지 않고 기능을 추가할 수 있도록 설계
LSP
차를 렌트할 때, 차의 브랜드와 상관 없이 운전자는 차를 똑같이 운전할 수 있어야 한다.
-> 부모(인터페이스)를 기준으로 만들어진 기능은, 자식 바꿔 끼워도 문제 없이 동작
ISP
스마트폰 사용자마다 필요한 어플리케이션만 다운 받아서 사용한다.
-> 사용자가 쓰는 기능만 제공받도록 설계
DIP
이어폰을 바꾸어도 음악이 잘 들려야 한다.
-> 고정된 구현이 나이라 추상적 연결(인터페이스)에 의존
댓글을 작성해보세요.