[λ””μžμΈνŒ¨ν„΄] μƒνƒœ νŒ¨ν„΄ , μŠ€ν…Œμ΄νŠΈ νŒ¨ν„΄ (State Pattern)

λ°˜μ‘ν˜•
πŸ’‘ μƒνƒœ νŒ¨ν„΄ , μŠ€ν…Œμ΄νŠΈ νŒ¨ν„΄ (state pattern)
객체의 λ‚΄λΆ€ μƒνƒœκ°€ λ°”λ€œμ— λ”°λΌμ„œ 객체의 행동을 λ°”κΏ€ 수 μžˆλ‹€. 마치 객체의 ν΄λž˜μŠ€κ°€ λ°”λ€ŒλŠ” 것과 같은 κ²°κ³Όλ₯Ό 얻을 수 μžˆλ‹€.

 

β–  μ˜ˆμ œ : 뽑기 자판기

(1) μš”κ΅¬μ‚¬ν•­

"λ‹€μŒκ³Ό 같은 λ°©μ‹μœΌλ‘œ μž‘λ™ν•˜λŠ” 뽑기 κΈ°κ³„μ˜ μžλ°”μ½”λ“œλ₯Ό μž‘μ„±ν•΄μ£Όμ„Έμš”. λ‚˜μ€‘μ— λ‹€λ₯Έ κΈ°λŠ₯을 μΆ”κ°€ν•  κ°€λŠ₯성도 μžˆμœΌλ‹ˆ μ΅œλŒ€ν•œ μœ μ—°ν•˜κ³  κ΄€λ¦¬ν•˜κΈ° μš©μ΄ν•œ λ””μžμΈμœΌλ‘œ ν•΄μ€¬μœΌλ©΄ ν•©λ‹ˆλ‹€."

μƒνƒœ λ‹€μ΄μ–΄κ·Έλž¨ (State Diagram)

μƒνƒœ λ‹€μ΄μ–΄κ·Έλž¨μ„ λ°”νƒ•μœΌλ‘œ μƒνƒœλ₯Ό μ •μ˜ν•˜μž.

  • μƒνƒœμ •μ˜
    • No Coin : 돈이 λ„£μ–΄μ Έμžˆμ§€ μ•Šμ€ μƒνƒœ
    • Has Coin : 돈 넣어진 μƒνƒœ
    • Sold : νŒλ§€μ€‘μ˜ μƒνƒœ
    • Sold Out : 맀진 μƒνƒœ

 

(2) λ¬Έμ œμΈμ‹

1. λ‹€μŒκ³Ό 같이 뽑기 자판기λ₯Ό μž‘μ„±ν•˜λ©΄ 될 것 κ°™λ‹€.

public class GachaMachine {
    // 각 μƒνƒœλ₯Ό μ €μž₯ν•˜κΈ°μœ„ν•œ μΈμŠ€ν„΄μŠ€λ³€μˆ˜λ₯Ό λ§Œλ“€μ–΄ μ •μ˜
    final static int SOLD_OUT = 0; // 맀진
    final static int NO_COIN = 1; // 동전 μ—†μŒ
    final static int HAS_COIN = 2; // 동전 있음
    final static int SOLD = 3; // 판맀

    int state = SOLD_OUT; // ν˜„μž¬ μƒνƒœλ₯Ό μ €μž₯ν•˜λŠ” μΈμŠ€ν„΄μŠ€ λ³€μˆ˜
    int count = 0; // 뽑기 갯수

    public GachaMachine(int count) {
        this.count = count;
        if (count > 0) {
            state = NO_COIN;
        }
    }

    public void insertCoin() {
        if (state == HAS_COIN) {
            // νŒλ§€λŒ€κΈ° μƒνƒœ : 동전 O
            System.out.println("동전이 이미 μžˆμ–΄μš”. 더 넣을 수 μ—†μ–΄μš”.");
        } else if (state == NO_COIN) {
            // νŒλ§€λŒ€κΈ° μƒνƒœ : 동전 X
            state = HAS_COIN;
            System.out.println("동전을 λ„£μ—ˆμŠ΅λ‹ˆλ‹€.");
        } else if (state == SOLD_OUT) {
            // 맀진 μƒνƒœ
            System.out.println("sold out! λ‹€ νŒ”λ Έμ–΄μš”. 돈 λ„£μ§€λ§ˆμ„Έμš”");
        } else if (state == SOLD) {
            // νŒλ§€μ€‘ μƒνƒœ
            System.out.println("μž μ‹œλ§Œ κΈ°λ‹€λ €μ£Όμ„Έμš”. 뽑기가 λ‚˜μ˜¬κ±°μ—μš”");
        }
    }

    public void ejectCoin() { // μ‚¬μš©μžκ°€ 동전 λ°˜ν™˜ ν•˜λŠ” 경우
        if (state == HAS_COIN) {
            // νŒλ§€λŒ€κΈ° : 동전 O, λ°˜ν™˜ O
            System.out.println("동전이 λ°˜ν™˜λ©λ‹ˆλ‹€.");
            state = NO_COIN;
        } else if (state == NO_COIN) {
            // νŒλ§€λŒ€κΈ° : 동전 X, λ°˜ν™˜ X
            System.out.println("동전이 μ—†μ–΄μš”");
        } else if (state == SOLD) {
            // νŒλ§€μ€‘ : 이미 νŒλ§€λ˜μ–΄ λ°˜ν™˜ X
            System.out.println("이미 κ΅¬μž… ν•˜μ…¨μ–΄μš”");
        } else if (state == SOLD_OUT) {
            // 맀진 : 동전 X, λ°˜ν™˜ X
            System.out.println("동전 λ°˜ν™˜ μ•ˆλΌμš”. λ§€μ§„μœΌλ‘œ λˆλ„ μ•ˆλ°›μ•˜μ–΄μš”");
        }
    }

    public void turnCrank() { // μ‚¬μš©μžκ°€ μ†μž‘μ΄λ₯Ό λŒλ¦¬λŠ” 경우
        if (state == SOLD) {
            System.out.println("μ†μž‘μ΄λŠ” ν•œ 번만 λŒλ €μ£Όμ„Έμš”.");
        } else if (state == NO_COIN) {
            System.out.println("동전을 λ„£μ–΄μ£Όμ„Έμš”");
        } else if (state == SOLD_OUT) {
            System.out.println("맀진 λ˜μ—ˆμŠ΅λ‹ˆλ‹€");
        } else if (state == HAS_COIN) {
            System.out.println("μ†μž‘μ΄λ₯Ό λŒλ ΈμŠ΅λ‹ˆλ‹€. 뽑기가 λ‚˜μ˜¬κ±°μ—μš”");
            state = SOLD;
            dispense();
        }
    }

    private void dispense() {
        if (state == SOLD) {
            System.out.println("뽑기가 λ‚˜κ°€κ³  μžˆμ–΄μš”");
            count = count - 1;
            if (count == 0) {
                System.out.println("뽑기 μž¬κ³ κ°€ μ—†μ–΄μš”");
                state = SOLD_OUT;
            } else {
                state = NO_COIN;
            }
        } else if (state == NO_COIN) {
            System.out.println("λ¨Όμ € 동전을 λ„£μ–΄μ£Όμ„Έμš”");
        } else if (state == SOLD_OUT) {
            System.out.println("맀진 μž…λ‹ˆλ‹€.");
        } else if (state == HAS_COIN) {
            System.out.println("뽑기가 λ‚˜κ°ˆ 수 μ—†μ–΄μš”.");
        }
    }
    // μ΄ν•˜ μ‚­μ œ
    public void refill(int numGumBalls) {
        this.count = numGumBalls;
        state = NO_COIN;
    }

    public String toString() {
        StringBuffer result = new StringBuffer();
        result.append("==== 뽑기 자판기 ==== \n");
        result.append("재고 : " + count + "  개");
        result.append("\nν˜„μž¬ 자판기 μƒνƒœλŠ” ");
        if (state == SOLD_OUT) {
            result.append("맀진 : sold out!!");
        } else if (state == NO_COIN) {
            result.append("νŒλ§€λŒ€κΈ°(돈 X) : 동전 λ„£μ–΄μ£Όμ„Έμš”");
        } else if (state == HAS_COIN) {
            result.append("νŒλ§€λŒ€κΈ°(돈 O) : μ†μž‘μ΄λ₯Ό λŒλ €μ£Όμ„Έμš”");
        } else if (state == SOLD) {
            result.append("νŒλ§€μ€‘ : 뽑기가 λ‚˜μ˜€κ³  μžˆμŠ΅λ‹ˆλ‹€.");
        }
        result.append("\n");
        return result.toString();
    }
}

2. λ³€κ²½μš”μ²­μ΄ λ“€μ–΄μ™”λ‹€. 뽑기에 1개λ₯Ό 더 받을 수 μžˆλŠ” κΈ°λŠ₯을 μΆ”κ°€ν•΄μ£Όμ„Έμš”.

"Buy 1 Get 1 : λ„μ „ν•˜μ„Έμš”! 10λΆ„μ˜ 1 ν™•λ₯ !"

μœ„μ™€κ°™μ€ μ†ŒμŠ€ μž‘μ„±λ°©λ²•μœΌλ‘œλŠ” λ‹€μŒκ³Ό 같이 μž‘μ„±ν•  수 밖에 μ—†λ‹€.

final static int SOLD_OUT = 0;
final static int NO_COIN = 1;
final static int HAS_COIN = 2;
final static int SOLD = 3;
// 1) μƒνƒœ κ°’ μ €μž₯을 μœ„ν•œ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜ μ„ μ–Έ : WINNER μƒνƒœλ₯Ό μΆ”κ°€ν•΄μ•Όν•œλ‹€.

// 2) 각 μƒνƒœ 쑰건문 : μΆ”κ°€ν•  λ•Œλ§ˆλ‹€ 각 λ©”μ†Œλ“œμ— if()λ₯Ό μ΄μš©ν•˜μ—¬ 쑰건을 μΆ”κ°€ν•΄μ•Ό ν•œλ‹€.
public void insertCoin () {
    // 동전 νˆ¬μž…μ‹œ ν•΄μ•Ό ν•  일 : νŒλ§€λŒ€κΈ°(동전o)
}
public void ejectCoin () {
    // 동전 λ°˜ν™˜μ‹œ ν•΄μ•Ό ν•  일 : 동전 λ°˜ν™˜ν›„ νŒλ§€λŒ€κΈ°(동전x) μƒνƒœμ„€μ •
}
public void turnCrank() {
    // μ†μž‘μ΄λ₯Ό λŒλ Έμ„ λ•Œ ν•΄μ•Ό ν•  일
}
public void dispense() {
    // 뽑기 λ‚΄λ³΄λ‚Όλ•Œ ν•΄μ•Ό ν•  일 : 남은 재고 νŒŒμ•…ν›„ μƒνƒœμ„€μ •
}

각 μƒνƒœ κ°’ μ €μž₯을 μœ„ν•œ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜κ°€ μΆ”κ°€λ˜κ³ , 각 μƒνƒœμ— λŒ€ν•œ if문의 쑰건을 μΆ”κ°€ν•΄μ•Όν•œλ‹€. μ°¨ν›„ μš”κ΅¬μ‚¬ν•­μ΄ 생기면 또 μΆ”κ°€ν•΄μ•Όν•˜κ³  κ·Έ μˆ˜κ°€ λ§Žμ•„μ§€λ©΄ 지저뢄해진닀.

 

(3) 문제점

ꡬ체적인 문제점 정리

  • OCP 원칙을 지킀지 μ•Šκ³  μžˆλ‹€.
  • 객체지ν–₯ λ””μžμΈμ΄λΌκ³  ν•˜κΈ°μ— 무리가 μžˆλ‹€.
  • μ§€μ €λ¬Έν•œ 쑰건문으둜 인해 μƒνƒœμ „ν™˜νžˆ λΆ„λͺ…ν•˜κ²Œ λ“œλŸ¬λ‚˜μ§€ μ•ŠλŠ”λ‹€.
  • λ‹€λ₯Έ κΈ°λŠ₯을 μΆ”κ°€ν•˜λŠ” κ³Όμ •μ—μ„œ κΈ°μ‘΄ μ½”λ“œμ— μ—†λ˜ μƒˆλ‘œμš΄ 버그가 λ°œμƒν•  κ°€λŠ₯성이 크닀.

즉, 각 μƒνƒœμ˜ 행동을 λ³„λ„μ˜ ν΄λž˜μŠ€μ— 집에 λ„£κ³  λͺ¨λ“  μƒνƒœμ—μ„œ 각자 μžκΈ°κ°€ ν•  일을 κ΅¬ν˜„ν•΄λ³΄μž.

 

λͺ¨λ“  μƒνƒœλ₯Ό μΊ‘μŠν™”μ‹œμΌœ State μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•΄λ³΄μž.

 

  • State μΈν„°νŽ˜μ΄μŠ€
    • λͺ¨λ“  μƒνƒœ ν΄λž˜μŠ€μ—μ„œ μ‚¬μš©ν•  μΈν„°νŽ˜μ΄μŠ€
    • λ©”μ†Œλ“œλŠ” 뽑기 κΈ°κ³„μ—μ„œ 일어날 수 μžˆλŠ” λͺ¨λ“  행동듀에 μ§μ ‘μ μœΌλ‘œ λŒ€μ‘λœλ‹€.
  • 각 μƒνƒœλ₯Ό λ‚˜νƒ€λ‚΄λŠ” ꡬ체 클래슀
    • 각 μƒνƒœλ₯Ό 직접 ν΄λž˜μŠ€μ— λŒ€μ‘μ‹œμΌœ μž‘μ„±ν•œλ‹€. 

 

 

β–  μƒˆλ‘œμš΄ λ””μžμΈ

  1. 뽑기 기계와 κ΄€λ ¨λœ λͺ¨λ“  행동에 λŒ€ν•œ λ©”μ†Œλ“œκ°€ λ“€μ–΄μžˆλŠ” State μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ •μ˜ν•œλ‹€.
  2. κΈ°κ³„μ˜ λͺ¨λ“  μƒνƒœμ— λŒ€ν•˜μ—¬ μƒνƒœ 클래슀λ₯Ό κ΅¬ν˜„ν•΄μ•Ό ν•œλ‹€. 기계가 μ–΄λ–€ μƒνƒœμ— μžˆλ‹€λ©΄, κ·Έ μƒνƒœμ— ν•΄λ‹Ήν•˜λŠ” μƒνƒœ ν΄λž˜μŠ€κ°€ λͺ¨λ“  μž‘μ—…μ„ μ±…μž„μ§€λ„λ‘ ν•œλ‹€.
  3. λ§ˆμ§€λ§‰μœΌλ‘œ 쑰건문 μ½”λ“œλ₯Ό μ „λΆ€ μ—†μ• κ³  μƒνƒœ ν΄λž˜μŠ€μ— λͺ¨λ“  μž‘μ—…μ„ μœ„μž„ν•œλ‹€.

1. State μΈν„°νŽ˜μ΄μŠ€

public interface State {
    void insertCoin();
    void ejectCoin();
    void turnCrank();
    void dispense();
    void refill();
}

2. 각 μƒνƒœ 클래슀 κ΅¬ν˜„

/**
 * νŒλ§€λŒ€κΈ° μƒνƒœ 정보 : 동전 O
 */
public class HasCoinState implements State {

    GachaMachine gachaMachine;

    public HasCoinState(GachaMachine gachaMachine) {
        this.gachaMachine = gachaMachine;
    }

    @Override
    public void insertCoin() {
        System.out.println("동전을 λ„£μ„μˆ˜ μ—†μ–΄μš”. 이미 동전이 μžˆμŠ΅λ‹ˆλ‹€.");
    }

    @Override
    public void ejectCoin() {
        // 동전 λ°˜ν™˜
        System.out.println("동전을 λ°˜ν™˜ν•©λ‹ˆλ‹€.");
        // 동전 λ°˜ν™˜ ν›„ 동전 μ—†μŒ μƒνƒœλ‘œ λ°”κΏ”μ€€λ‹€.
        gachaMachine.setState(gachaMachine.getNoCoinState());
    }

    @Override
    public void turnCrank() {
        // μ†μž‘μ΄ 돌리기
        System.out.println("μ†μž‘μ΄λ₯Ό λŒλ¦½λ‹ˆλ‹€.");
        // μ†μž‘μ΄ 돌린 κ²°κ³Ό : 뽑기 판맀 μ‹œμž‘
        gachaMachine.setState(gachaMachine.getSoldState());
    }

    @Override
    public void dispense() {
        System.out.println("뽑기 아직 λ‚˜μ˜€μ§€ μ•Šμ•˜μ–΄μš”.");
    }

    @Override
    public void refill() {

    }

    @Override
    public String toString() {
        return "νŒλ§€λŒ€κΈ° μƒνƒœμž…λ‹ˆλ‹€ : μ†μž‘μ΄λ₯Ό λŒλ €μ•Ό 뽑기가 λ‚˜μ˜΅λ‹ˆλ‹€.";
    }
}
/**
 * νŒλ§€λŒ€κΈ° μƒνƒœ 정보 : 동전 X
 */
public class NoCoinState implements State {

    GachaMachine gachaMachine;

    public NoCoinState(GachaMachine gachaMachine) {
        this.gachaMachine = gachaMachine;
    }

    @Override
    public void insertCoin() {
        System.out.println("동전을 λ„£μŠ΅λ‹ˆλ‹€.");
        gachaMachine.setState(gachaMachine.getHasCoinState());
    }

    @Override
    public void ejectCoin() {
        System.out.println("동전이 μ—†μŠ΅λ‹ˆλ‹€. 동전을 λ°˜ν™˜ν•  수 μ—†μ–΄μš”.");
    }

    @Override
    public void turnCrank() {
        System.out.println("동전이 μ—†μŠ΅λ‹ˆλ‹€. μ†μž‘μ΄λ₯Ό λŒλ €λ„ 뽑기가 λ‚˜μ˜€μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.");
    }

    @Override
    public void dispense() {
        System.out.println("동전을 λ„£μ–΄μ£Όμ„Έμš”.");
    }

    @Override
    public void refill() {

    }

    @Override
    public String toString() {
        return "νŒλ§€λŒ€κΈ° μƒνƒœμž…λ‹ˆλ‹€ : 동전을 λ„£μ–΄μ£Όμ„Έμš”.";
    }
}
/**
 * 맀진 μƒνƒœ 정보
 */
public class SoldOutState implements State {

    GachaMachine gachaMachine;

    public SoldOutState(GachaMachine gachaMachine) {
        this.gachaMachine = gachaMachine;
    }

    @Override
    public void insertCoin() {
        System.out.println("λ§€μ§„μž…λ‹ˆλ‹€. 동전을 λ„£μ§€λ§ˆμ„Έμš”");
    }

    @Override
    public void ejectCoin() {
        System.out.println("넣은 동전이 μ—†μŠ΅λ‹ˆλ‹€.");
    }

    @Override
    public void turnCrank() {
        System.out.println("동전을 λ„£μ–΄μ£Όμ„Έμš”.");
    }

    @Override
    public void dispense() {
        System.out.println("뽑기가 μ—†μŠ΅λ‹ˆλ‹€.");
    }

    @Override
    public void refill() {
        gachaMachine.setState(gachaMachine.getNoCoinState());
    }

    @Override
    public String toString() {
        return "맀진 μƒνƒœμž…λ‹ˆλ‹€. sold out!!";
    }
}
/**
 * νŒλ§€μ€‘ μƒνƒœ
 */
public class SoldState implements State {

    GachaMachine gachaMachine;

    public SoldState(GachaMachine gachaMachine) {
        this.gachaMachine = gachaMachine;
    }

    @Override
    public void insertCoin() {
        System.out.println("μž μ‹œλ§Œ κΈ°λ‹€λ €μ£Όμ„Έμš”. μ§€κΈˆ 뽑기가 λ‚˜μ˜€κ³  μžˆμŠ΅λ‹ˆλ‹€.");
    }

    @Override
    public void ejectCoin() {
        System.out.println("μ£„μ†‘ν•©λ‹ˆλ‹€. 이미 뽑기가 λ‚˜μ˜€κ³ μžˆμ–΄ ν™˜λΆˆμ΄ λΆˆκ°€ν•©λ‹ˆλ‹€.");
    }

    @Override
    public void turnCrank() {
        System.out.println("μž μ‹œλ§Œ κΈ°λ‹€λ €μ£Όμ„Έμš”. 이미 뽑기가 λ‚˜μ˜€κ³  μžˆμŠ΅λ‹ˆλ‹€.");
    }

    @Override
    public void dispense() {
        // 뽑기 판맀 처리
        gachaMachine.releaseBall();
        // 뽑기 판맀 ν›„ μž¬κ³ ν™•μΈν•΄μ„œ μƒνƒœλ₯Ό λ°”κΏ”μ€€λ‹€.
        if (gachaMachine.getCount() > 0) {
            // 뽑기 μž¬κ³ κ°€ 있으면, νŒλ§€λŒ€κΈ° μƒνƒœ
            gachaMachine.setState(gachaMachine.getNoCoinState());
        } else {
            // 뽑기 μž¬κ³ κ°€ μ—†μœΌλ©΄, 맀진 μƒνƒœ
            System.out.println("뽑기가 λ§€μ§„λ˜μ—ˆμŠ΅λ‹ˆλ‹€.");
            gachaMachine.setState(gachaMachine.getSoldOutState());
        }
    }

    @Override
    public void refill() {
    }

    @Override
    public String toString() {
        return "νŒλ§€μ€‘ μƒνƒœμž…λ‹ˆλ‹€ : 뽑기 νŒλ§€μ€‘!";
    }
}

3. 뽑기 기계 λ§Œλ“€κΈ°

public class GachaMachine {

    State soldOutState; // 맀진 μƒνƒœ
    State noCoinState; // νŒλ§€λŒ€κΈ° μƒνƒœ : 코인 μ—†λŠ” μƒνƒœ
    State hasCoinState; // νŒλ§€λŒ€κΈ° μƒνƒœ : 코인 넣어진 μƒνƒœ
    State soldState; // νŒλ§€μ€‘μ˜ μƒνƒœ
    State state; // μƒνƒœ μΈμŠ€ν„΄μŠ€
    int count = 0; // 뽑기 개수

    public GachaMachine(int numberGumballs) {
        soldOutState = new SoldOutState(this);
        noCoinState = new NoCoinState(this);
        hasCoinState = new HasCoinState(this);
        soldState = new SoldState(this);

        this.count = numberGumballs;
        if (numberGumballs > 0) {
            state = noCoinState;
        } else {
            state = soldOutState;
        }
    }

    public void insertCoin() {
        // 동전 λ„£μŒ
        state.insertCoin();
    }

    public void ejectCoin() {
        // 동전 λ°˜ν™˜μ„ ν•˜λ©΄ λ°˜ν™˜
        state.ejectCoin();
    }

    public void turnCrank() {
        // μ†μž‘μ΄ 돌림
        state.turnCrank();
        // 뽑기 νŒλ§€μ—¬λΆ€
        state.dispense();
    }

    public void releaseBall() {
        System.out.println("뽑기가 λ‚˜μ™”μŠ΅λ‹ˆλ‹€.");
        if (count > 0) {
            count = count - 1;
        }
    }

    public void refill(int count) {
        this.count = this.count + count;
        System.out.println("뽑기 " + count + " 개 리필!, ν˜„μž¬ " + this.count + " 개 μž…λ‹ˆλ‹€.");
        state.refill();
    }

    public void setState(State state) {
        this.state = state;
    }

    public int getCount() {
        return count;
    }

    public State getState() {
        return state;
    }

    public State getSoldOutState() {
        return soldOutState;
    }

    public State getNoCoinState() {
        return noCoinState;
    }

    public State getHasCoinState() {
        return hasCoinState;
    }

    public State getSoldState() {
        return soldState;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("===== Gumball Machine =====\n");
        sb.append("λ¨Έμ‹  μƒνƒœ : " + state + "\n");
        sb.append("재고 : " + count + " 개\n");
        return sb.toString();
    }
}

 

μ •λ¦¬ν•˜λ©΄

  • 각 State 의 행동 (Behavior) 을 λ³„κ°œμ˜ 클래슀둜 ꡭ지화 μ‹œμΌ°λ‹€.
  • μ§€μ €λΆ„ν•œ if문듀을 μ‚­μ œν–ˆλ‹€.
  • 각 State λ₯Ό λ³€κ²½ν•˜λŠ” 것에 λŒ€ν•΄μ„œλŠ” λ‹«ν˜€μžˆμœΌλ©΄μ„œ GachaMachine μžμ²΄λŠ” μƒˆλ‘œμš΄ μƒνƒœ 클래슀λ₯Ό μΆ”κ°€ν•˜λŠ” ν™•μž₯에 λŒ€ν•΄μ„œλŠ” μ—΄λ €μžˆλ‹€. (OCP 원칙)
  • μ²˜μŒμ— μš”κ΅¬λ°›μ€ μƒνƒœ λ‹€μ΄μ–΄κ·Έλž¨μ— 훨씬 κ°€κΉŒμš°λ©΄μ„œλ„ μ΄ν•΄ν•˜κΈ° 쒋은 μ½”λ“œ λ² μ΄μŠ€μ™€ 클래슀 ꡬ쑰λ₯Ό λ§Œλ“€μ—ˆλ‹€.

 

β–  μŠ€ν…Œμ΄νŠΈ νŒ¨ν„΄μ˜ 적용 효과

  1. λ‚΄λΆ€ μƒνƒœκ°€ λ°”λ€œμ— λ”°λΌμ„œ 객체의 행동을 λ°”κΏ€ 수 μžˆλ‹€.
    μƒνƒœλ₯Ό λ³„λ„μ˜ 클래슀둜 μΊ‘μŠν™”ν•œ λ‹€μŒ ν˜„μž¬ μƒνƒœμ— μžˆλŠ” κ°μ²΄μ—κ²Œ 행동을 μœ„μž„ν•˜κΈ° λ•Œλ¬Έμ— λ‚΄λΆ€ μƒνƒœκ°€ λ°”λ€œμ— λ”°λΌμ„œ 행동이 λ‹¬λΌμ§€κ²Œ λ˜λŠ” 것이닀.
  2. ν΄λž˜μŠ€κ°€ λ°”λ€ŒλŠ” 것 같은 κ²°κ³Όλ₯Ό μ–»λŠ”λ‹€.
    ν΄λΌμ΄μ–ΈνŠΈ μž…μž₯μ—μ„œ ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ μ‚¬μš©ν•˜λŠ” 객체의 행동이 μ™„μ „νžˆ λ‹¬λΌμ§ˆ 수 μžˆλ‹€λ©΄ 마치 κ·Έ 객체가 λ‹€λ₯Έ ν΄λž˜μŠ€λ‘œλΆ€ν„° λ§Œλ“€μ–΄μ§„ 객체처럼 느껴질 수 μžˆλ‹€. μ‹€μ œλ‘œλŠ” λ‹€λ₯Έ 클래슀둜 λ§Œλ“€μ–΄μ Έ λ³€μ‹ ν•˜λŠ” 것이 μ•„λ‹ˆλΌ ꡬ성을 톡해 μ—¬λŸ¬ μƒνƒœ 객체λ₯Ό λ°”κΏ”κ°€λ©΄μ„œ μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— λ°”λ€ŒλŠ” 것과 같은 κ²°κ³Όλ₯Ό 얻을 수 μžˆλŠ” 것이닀.

 

 

β–  UML Diagram

Strategy Pattern (μ „λž΅ νŒ¨ν„΄ , μŠ€νŠΈλž˜ν‹°μ§€ νŒ¨ν„΄) κ³Ό UML Diagram 이 λ™μΌν•˜λ‹€.

 

β–  Strategy Pattern κ³Ό 차이

μš©λ„μ— μžˆμ–΄μ„œ 차이점이 μžˆλ‹€.

Strategy νŒ¨ν„΄ State νŒ¨ν„΄
일반적으둜 Client μ—μ„œ Context κ°μ²΄ν•œν…Œ μ–΄λ–€ μ „λž΅μ„ μ‚¬μš©ν• μ§€ 지정해쀀닀.
주둜 μ‹€ν–‰μ‹œμ— μ „λž΅ 객체 (Strategy Object) λ₯Ό λ³€κ²½ν•  수 μžˆλŠ” μœ μ—°μ„±μ„ μ œκ³΅ν•˜κΈ° μœ„ν•œ μš©λ„λ‘œ 쓰인닀.
State 객체에 행동이 μΊ‘μŠν™” λœλ‹€.
상황에 따라 Context κ°μ²΄μ—μ„œ μ—¬λŸ¬ State 객체 쀑 ν•˜λ‚˜μ˜ κ°μ²΄μ—κ²Œ λͺ¨λ“  행동을 맑기게 λœλ‹€.
즉, Client λŠ” State 객체에 λŒ€ν•΄ μžμ„Ένžˆ λͺ°λΌλ„ λœλ‹€.
SubClass λ₯Ό λ§Œλ“œλŠ” 방법을 λŒ€μ‹ ν•˜μ—¬ μœ μ—°μ„±μ„ κ·ΉλŒ€ν™” ν•˜κΈ° μœ„ν•œ μš©λ„λ‘œ μ‚¬μš©ν•œλ‹€.
상속을 μ΄μš©ν•΄μ„œ 클래슀의 행동을 μ •μ˜ν•˜λ‹€λ³΄λ©΄ 행동을 μ‰½κ²Œ λ³€κ²½ν•˜κΈ° μ–΄λ ΅μ§€λ§Œ, Strategy νŒ¨ν„΄μ„ μ‚¬μš©ν•˜λ©΄ ꡬ성을 톡해 행동을 μ •μ˜ν•˜λŠ” 객체λ₯Ό μœ μ—°ν•˜κ²Œ λ°”κΏ€ 수 μžˆλ‹€.
Context 객체에 μ§€μ €λΆ„ν•˜κ²Œ 쑰건문을 λ„£λŠ” λŒ€μ‹  μ‚¬μš©ν•  수 μžˆλŠ” νŒ¨ν„΄μ΄λΌ ν•  수 μžˆλ‹€.

 

β–  μ •λ¦¬

  • State νŒ¨ν„΄μ„ μ΄μš©ν•˜λ©΄ λ‚΄λΆ€ μƒνƒœλ₯Ό λ°”νƒ•μœΌλ‘œ μ—¬λŸ¬ λ‹€λ₯Έ 행동을 μ‚¬μš©ν•  수 μžˆλ‹€.
  • 쑰건문 등을 μ΄μš©ν•˜μ—¬ μ§€μ €λΆ„ν•˜κ²Œ μƒνƒœλ₯Ό λ‚˜νƒ€λ‚΄μ§€ μ•Šκ³  각 μƒνƒœλ₯Ό 클래슀λ₯Ό μ΄μš©ν•˜μ—¬ ν‘œν˜„ν•˜κ²Œλœλ‹€.
  • 각 μƒνƒœλ₯Ό 클래슀둜 μΊ‘μŠν™” ν•¨μœΌλ‘œμ¨ λ‚˜μ€‘μ— λ³€κ²½μ‹œμΌœμ•Ό ν•  λ‚΄μš©μ„ ꡭ지화 ν•  수 μžˆλ‹€.
  • 일반적으둜 행동 λ˜λŠ” μ•Œκ³ λ¦¬μ¦˜μ„ Context 클래슀λ₯Ό λ§Œλ“€ λ•Œ μ„€μ •ν•œλ‹€.
  • μƒνƒœ μ „ν™˜μ€ State ν΄λž˜μŠ€μ— μ˜ν•΄μ„œ μ œμ–΄ν•  μˆ˜λ„ 있고, Context ν΄λž˜μŠ€μ— μ˜ν•΄μ„œ μ œμ–΄ν•  μˆ˜λ„ μžˆλ‹€.
  • μƒνƒœλ₯Ό 클래슀둜 μƒμ„±ν•˜κΈ°λ•Œλ¬Έμ— 클래슀의 κ°œμˆ˜κ°€ λŠ˜μ–΄λ‚  수 μžˆμ§€λ§Œ 상황에 따라 클래슀의 μˆ˜κ°€ 더 λ§Žμ€νŽΈμ΄ λ‚˜μ„ 수 μžˆλ‹€.
  • State 클래슀λ₯Ό μ—¬λŸ¬ Context 객체의 μΈμŠ€ν„΄μŠ€μ—μ„œ κ³΅μœ ν•˜λ„λ‘ ν•  μˆ˜λ„ μžˆλ‹€.

 


μ°Έκ³ 
ν—€λ“œ 퍼슀트 λ””μžμΈ νŒ¨ν„΄ (Head First Design Patterns) - 에릭 프리먼,μ—˜λ¦¬μžλ² μŠ€ 둭슨,μΌ€μ΄μ‹œ μ‹œμ—λΌ,λ²„νŠΈ 베이츠

 

λ°˜μ‘ν˜•