본문 바로가기
객체지향

🚫 else 금지 이유와 개선 법

by 순원이 2024. 11. 12.

🚫 else를 사용할 때의 단점

1. 두 가지 이상의 책임

// ❌ else를 사용하면 하나의 메서드가 성공/실패 두 가지 책임을 가짐
public void processPayment(Payment payment) {
    if (payment.isValid()) {
        // 결제 성공 처리
        payment.approve();
        notifySuccess();
        savePaymentHistory();
    } else {
        // 결제 실패 처리
        payment.reject();
        notifyFailure();
        saveFailureHistory();
    }
}

// ✅ 실패는 빠르게 리턴하고 성공 로직만 남김
public void processPayment(Payment payment) {
    if (!payment.isValid()) {
        handleFailure(payment);
        return;
    }

    // 결제 성공 처리만 담당
    payment.approve();
    notifySuccess();
    savePaymentHistory();
}

2. 조건의 불명확성

// ❌ else는 '그 외 모든 경우'를 의미해서 모호함
public String getGradeMessage(int score) {
    if (score >= 90) {
        return "A등급입니다";
    } else {
        return "A등급이 아닙니다";  // 어떤 점수가 여기로 오는지 불명확
    }
}

// ✅ 모든 조건을 명시적으로 표현
public String getGradeMessage(int score) {
    if (score >= 90) {
        return "A등급입니다";
    }
    if (score >= 80) {
        return "B등급입니다";
    }
    return "C등급입니다";
}

3. 코드 추가의 위험성

// ❌ else 블록에 코드를 추가하면 실수하기 쉬움
public void moveCar(Car car) {
    if (car.isMovable()) {
        car.move();
    } else {
        // 나중에 여기에 코드를 추가하면서
        // 예외처리를 깜빡하거나
        // 잘못된 로직을 넣기 쉬움
        car.stop();
    }
}

// ✅ 명확한 조건으로 분리
public void moveCar(Car car) {
    if (!car.isMovable()) {
        throw new IllegalStateException("자동차가 이동할 수 없는 상태입니다.");
    }
    car.move();
}


💡 개선 방법

1. Early Return

public void processPayment(Payment payment) {
    if (!payment.isValid()) {
        throw new IllegalArgumentException("유효하지 않은 결제입니다.");
    }
    if (!payment.hasEnoughBalance()) {
        throw new IllegalStateException("잔액이 부족합니다.");
    }
    // 결제 처리 로직
}

2. 객체 분리

public interface PaymentProcessor {
    void process();
}

public class CreditCardProcessor implements PaymentProcessor {
    @Override
    public void process() {
        // 신용카드 결제 처리
    }
}

public class CashProcessor implements PaymentProcessor {
    @Override
    public void process() {
        // 현금 결제 처리
    }
}

3. Enum 활용

public enum OrderStatus {
    READY {
        @Override
        public int calculatePrice() {
            return 1000;
        }
    },
    PROCESSING {
        @Override
        public int calculatePrice() {
            return 2000;
        }
    };

    public abstract int calculatePrice();
}

🌟 장점

  1. 조건문이 줄어들어 핵심 로직이 더 잘 보임
  2. 새로운 상태나 조건 추가가 용이
  3. 각 객체별로 독립적인 테스트 가능
  4. 각 객체가 명확한 하나의 책임만 가짐
  5. 새로운 요구사항 추가가 쉬움

🎓 결론

else와 삼항연산자를 무조건 피하라는 게 아니라, 더 나은 객체지향적 해결방법이 있다면 그것을 선택하라는 의미입니다. 단순한 상황에서는 사용해도 괜찮습니다! 👍