Refactoring Java Spring Boot Code: Eliminating If-Else Statements for Cleaner, Extensible Logic
Medium
If-else 문은 흔하지만 남용되면 복잡하고 유지보수가 어려운 코드로 이어질 수 있습니다. 이 글에서는 Java Spring Boot 프로젝트에서 if-else 문을 줄이기 위한 다양한 전략을 탐구하여 코드를 더 모듈화하고, 유지보수하기 쉽고, 읽기 쉽게 만드는 방법에 대해 설명하겠습니다.
If-Else 문을 줄이는 전략
전략 패턴(Strategy Pattern)
Enum 사용
다형성(Polymorphism)
람다 표현식과 함수형 인터페이스
명령 패턴(Command Pattern)
가드 절(Guard Clauses)
1. 전략 패턴
전략 패턴은 알고리즘의 가족을 정의하고, 각각을 캡슐화하며, 이들을 상호 교환 가능하게 만듭니다. 여러 가지 방법으로 특정 작업을 수행해야 할 때 유용합니다.
예제: 결제 처리 시스템
먼저 PaymentStrategy 인터페이스를 정의합니다:
public interface PaymentStrategy {
void pay(double amount);
}
그런 다음, 다른 결제 전략을 구현합니다:
@Component
public class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(double amount) {
// 신용 카드 결제 처리 로직
System.out.println("Paid " + amount + " using Credit Card.");
}
}
@Component
public class PaypalPayment implements PaymentStrategy {
@Override
public void pay(double amount) {
// PayPal 결제 처리 로직
System.out.println("Paid " + amount + " using PayPal.");
}
}
2. Enum 사용
Enums는 미리 정의된 상수 집합과 그와 관련된 동작을 나타내는 데 사용할 수 있습니다.
예제: 주문 상태 관리
다양한 동작을 가진 OrderStatus enum을 정의합니다:
public enum OrderStatus {
NEW {
@Override
public void handle() {
System.out.println("Processing new order.");
}
},
SHIPPED {
@Override
public void handle() {
System.out.println("Order shipped.");
}
},
DELIVERED {
@Override
public void handle() {
System.out.println("Order delivered.");
}
};
public abstract void handle();
}
3. 다형성 (Polymorphism)
다형성은 객체를 실제 클래스가 아닌 부모 클래스의 인스턴스로 취급할 수 있게 해줍니다. 이를 통해 부모 클래스의 참조를 통해 파생 클래스의 재정의된 메서드를 호출할 수 있습니다.
예제: 알림 시스템
Notification 인터페이스와 그 구현을 정의합니다:
public interface Notification {
void send(String message);
}
public class EmailNotification implements Notification {
@Override
public void send(String message) {
// 이메일 전송 로직
System.out.println("Sending email: " + message);
}
}
public class SmsNotification implements Notification {
@Override
public void send(String message) {
// SMS 전송 로직
System.out.println("Sending SMS: " + message);
}
}
4. 람다 표현식과 함수형 인터페이스
람다 표현식은 특히 단일 메서드 인터페이스를 다룰 때 코드를 간소화할 수 있습니다.
예제: 할인 서비스
람다 표현식을 사용하는 할인 서비스를 정의합니다:
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
public class DiscountService {
private Map<String, Function<Double, Double>> discountStrategies = new HashMap<>();
public DiscountService() {
discountStrategies.put("SUMMER_SALE", price -> price * 0.9);
discountStrategies.put("WINTER_SALE", price -> price * 0.8);
}
public double applyDiscount(String discountCode, double price) {
return discountStrategies.getOrDefault(discountCode, Function.identity()).apply(price);
}
}
5. 명령 패턴 (Command Pattern)
명령 패턴은 요청을 객체로 캡슐화하여 클라이언트를 큐, 요청, 작업으로 매개변수화할 수 있게 합니다.
예제: 파일 작업
Command 인터페이스와 구체적인 명령을 정의합니다:
public interface Command {
void execute();
}
public class OpenFileCommand implements Command {
private FileSystemReceiver fileSystem;
public OpenFileCommand(FileSystemReceiver fs) {
this.fileSystem = fs;
}
@Override
public void execute() {
this.fileSystem.openFile();
}
}
public class CloseFileCommand implements Command {
private FileSystemReceiver fileSystem;
public CloseFileCommand(FileSystemReceiver fs) {
this.fileSystem = fs;
}
@Override
public void execute() {
this.fileSystem.closeFile();
}
}
6. 가드 절 (Guard Clauses)
가드 절은 조건을 미리 처리하여 중첩 구조를 줄이고 코드를 더 읽기 쉽게 만듭니다.
예제: 사용자 검증
사용자 입력을 검증하기 위해 if-else 문을 중첩하는 대신, 가드 절을 사용하여 잘못된 경우를 미리 처리합니다:
public class UserService {
public void registerUser(User user) {
if (user == null) {
throw new IllegalArgumentException("User cannot be null");
}
if (user.getName() == null || user.getName().isEmpty()) {
throw new IllegalArgumentException("User name cannot be empty");
}
if (user.getEmail() == null || user.getEmail().isEmpty()) {
throw new IllegalArgumentException("User email cannot be empty");
}
// 등록 진행
System.out.println("Registering user: " + user.getName());
}
}
결론
이러한 전략을 적용함으로써 Java Spring Boot 프로젝트에서 if-else 문의 사용을 크게 줄일 수 있습니다. 이는 코드의 가독성을 높이고 유지보수성과 확장성을 향상시킵니다. 이러한 패턴과 관행을 채택하여 더 깨끗하고 효율적인 코드를 작성하세요.
번역: [https://ducktopia.tistory.com/129]
원문:
다음 내용이 궁금하다면?
이미 회원이신가요?
2024년 7월 10일 오후 12:39
이런 거 신입이 보고 if-else 써야할때 안쓸까봐 두려워요...
@triplehoon 써야할땐 당연히 써야하는게 맞죠 무분별한 중첩문 대신에 이런 방법은 어떨까? 하고 소개하는 글이라고 봐주시면 됩니다!
전략패턴과 다형성 예제를 보면 같아 보이는데 혹시 어떤 차이가 있는지 설명 부탁 드려도 될까요?
@김정진 해당 패턴을 사용하는 방식에서 차이가 있는 것 같아요 상응하는 예제를 제가 생략해서(...) 원문 들어가보시면 더 상세히 설명이 되어 있습니다
@조서희 감사합니다 ㅎ 항상 잘 보고 있어요 ㅎ 좋은글 감사해요 ☺️
if else 를 줄이기 위한 목적으로 다형성이나 전략 패턴을 활용한다는게 조금 과하게 느껴지기는 하네요. 전략패턴이 적용된 인터페이스를 어떻게 활용하는지도 중요한데 자칫하면 if else 를 상위 레이어에 올릴 뿐일 수도 있습니다. 상황이라는 것이 매우 다양할텐데 위에 제시해주신 방식을 적용해야하는 케이스들이 좀 더 구체적으로 제시되는 것이 좋지 않을까 싶습니다. 추상화는 확장성에는 유리하지만 가독성을 떨어뜨랄 수 있을 것 같아요. 개인적으로는 가드절 정도가 범용적으로 적용할 수 있는 방법이 아닌가 싶습니다. 그리고 이런 방법들은 springboot 에서 사용하는 방법이라기 보다는 범용적인 프로그래밍 방법으로 보아야하지 않을까요
@김도원 저도 가드절 정도만 써본 것 같아요 그정도가 적당하다는 것에 동의합니다 예제를 스프링부트 기준으로 작성했기 때문에 제목을 그렇게 지은게 아닐까 싶어요 😅
if-else문을 줄이기 위한 방법으로는 조금 과한면이 있는거 같네요..
@임주빈 동의합니다. 가드절 정도만 유용하게 쓸 수 있을 것 같아요
좀 복잡한 도메인의 게임 쪽은 if - else 쓰면 뚜두러 맞는 다는 소문이 ㅎㅎ