🕊️ Java Spring Boot에서 If-Else문 줄이기

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]

원문:

Refactoring Java Spring Boot Code: Eliminating If-Else Statements for Cleaner, Extensible Logic

Medium

Refactoring Java Spring Boot Code: Eliminating If-Else Statements for Cleaner, Extensible Logic

다음 내용이 궁금하다면?

또는

이미 회원이신가요?

2024년 7월 10일 오후 12:39

 • 

저장 334조회 13,220

댓글 10

  • 이런 거 신입이 보고 if-else 써야할때 안쓸까봐 두려워요...

    @triplehoon 써야할땐 당연히 써야하는게 맞죠 무분별한 중첩문 대신에 이런 방법은 어떨까? 하고 소개하는 글이라고 봐주시면 됩니다!

  • 전략패턴과 다형성 예제를 보면 같아 보이는데 혹시 어떤 차이가 있는지 설명 부탁 드려도 될까요?

    @김정진 해당 패턴을 사용하는 방식에서 차이가 있는 것 같아요 상응하는 예제를 제가 생략해서(...) 원문 들어가보시면 더 상세히 설명이 되어 있습니다

    @조서희 감사합니다 ㅎ 항상 잘 보고 있어요 ㅎ 좋은글 감사해요 ☺️

  • if else 를 줄이기 위한 목적으로 다형성이나 전략 패턴을 활용한다는게 조금 과하게 느껴지기는 하네요. 전략패턴이 적용된 인터페이스를 어떻게 활용하는지도 중요한데 자칫하면 if else 를 상위 레이어에 올릴 뿐일 수도 있습니다. 상황이라는 것이 매우 다양할텐데 위에 제시해주신 방식을 적용해야하는 케이스들이 좀 더 구체적으로 제시되는 것이 좋지 않을까 싶습니다. 추상화는 확장성에는 유리하지만 가독성을 떨어뜨랄 수 있을 것 같아요. 개인적으로는 가드절 정도가 범용적으로 적용할 수 있는 방법이 아닌가 싶습니다. 그리고 이런 방법들은 springboot 에서 사용하는 방법이라기 보다는 범용적인 프로그래밍 방법으로 보아야하지 않을까요

    @김도원 저도 가드절 정도만 써본 것 같아요 그정도가 적당하다는 것에 동의합니다 예제를 스프링부트 기준으로 작성했기 때문에 제목을 그렇게 지은게 아닐까 싶어요 😅

  • if-else문을 줄이기 위한 방법으로는 조금 과한면이 있는거 같네요..

    @임주빈 동의합니다. 가드절 정도만 유용하게 쓸 수 있을 것 같아요

  • 좀 복잡한 도메인의 게임 쪽은 if - else 쓰면 뚜두러 맞는 다는 소문이 ㅎㅎ