본문 바로가기

디자인패턴/내 코드가 그렇게 이상한가요?

분기문 적게 쓰는 법 - 내 코드가 그렇게 이상한가요? 6장 요약 (2)

 

 

조건 분기문의 중첩을 interface로 대체하기

3가지 조건 중 3가지 모두를 만족하는 경우 골드 회원, 2가지만 만족하면 실버 회원, 1가지만 만족하면 브론즈 회원이라고 해보자. 골드 회원인지 여부를 판단하기 위해 다음과 같이 if문을 세 번 중첩해서 로직을 구현할 수도 있을 것이다. 

// 3가지 조건을 모두 충족하는지 확인하기 위해
// 3번의 if문 중첩
boolean isGoldCustomer(PurchaseHistory history) {
    if (100000 <= history.totalAmount) {
    	if (10 <= history.purchaseFrequencyPerMonth) {
        	if (history.returnRate <= 0.001) {
            	return true;
            }
        }
    }
    return false;
}

 

이때 각 조건을 if문 조건부에 쓰는 대신, "MembershipRule" 이라는 이름의 인터페이스의 구현체로 묶어보자.

// 인터페이스로 룰을 추상화 시킴
interface MembershipRule {
    boolean ok (final PurchaseHistory history);
}
// 구체적인 룰을 Concrete Class로 구현
class PurchaseAmountRule implements MembershipRule {
    public boolean ok(final PurchaseHistory history) {
        return 1000000 <= history.totalAmount;
    }
}

class PurchaseFrequencyRule implements MembershipRule {
    public boolean ok(final PurchaseHistory history) {
        return 10 <= history.purchaseFrequencyPerMonth;
    }
}

class ReturnRateRule implements MembershipRule {
    public boolean ok(final PurchaseHistory history) {
        return history.returnRate <= 0.001;
    }
}

 

이제 원하는 룰을 담을 수 있도록 Policy라는 클래스를 만들어 GoldPolicy, SilverPolicy, BronzePolicy를 만들 수 있도록 한다. Policy 클래스는 룰을 Set으로 가지고 있고, 룰을 추가하는 add()와 모든 rule을 충족하는지 검사하는 complyAll()을 가진다.

class MembershipPolicy {
    private final Set<MembershipRule> rules;
    
    MembershipPolicy() {
        rules = new HashSet();
    }
    
    void add(final MembershipRule rule) {
        rules.add(rule);
    }
    
    boolean complyAll(final PurchaseHistory history) {
        for (MembershipRule rule : rules) {
            if(!rule.ok(history)) return false;
        }
        return true;
    }
}

 

이제 골드회원 판정 로직을 수정해보면 다음과 같다.

class GoldMembershipPolicy {
    private final MembershipPolicy policy;
    
    GoldMembershipPolicy() {
        policy = new MembershipPolicy();
        policy.add(new PurchaseAmountRule());
        policy.add(new PurchaseFrequencyRule());
        policy.add(new ReturnRateRule());
    }
    
    boolean complyAll(final PurchaseHistory history) {
        return policy.complyAll(history);
    }
}