๊ด€๋ฆฌ ๋ฉ”๋‰ด

deVlog

[๋””์ž์ธ ํŒจํ„ด] ํ–‰์œ„ ํŒจํ„ด - Strategy Pattern (์ „๋žต ํŒจํ„ด) ๋ณธ๋ฌธ

๐Ÿ› ๏ธ Software Architecture/Design Pattern

[๋””์ž์ธ ํŒจํ„ด] ํ–‰์œ„ ํŒจํ„ด - Strategy Pattern (์ „๋žต ํŒจํ„ด)

์€๋ฃจ๋ฐ 2024. 6. 10. 22:54

๋ชฉ์ฐจ

     

     

    ๐Ÿ“‡ ๊ฐœ์š”

    ์ „๋žต ํŒจํ„ด(Strategy Pattern)์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์บก์Аํ™”ํ•˜์—ฌ ์‹คํ–‰ ์ค‘์— ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์„ ํƒํ•˜๊ณ  ๊ต์ฒดํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด์ด๋‹ค. ์ฆ‰, ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์—ฌ๋Ÿฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ณ„๋„์˜ ํด๋ž˜์Šค๋กœ ๋ถ„๋ฆฌํ•˜๊ณ , ์ด๋“ค์„ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ๊ต์ฒด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฐฉ์‹์ด๋‹ค.

     

    ํŠน์ง•

    • ํ–‰์œ„(์•Œ๊ณ ๋ฆฌ์ฆ˜)๋ฅผ ํด๋ž˜์Šค๋กœ ์บก์Аํ™”ํ•˜์—ฌ ๋™์ ์œผ๋กœ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์ปจํ…์ŠคํŠธ(Context)์™€ ์ „๋žต(Strategy)์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ˜๋‹ค.
    • OCP(๊ฐœ๋ฐฉ-ํ์‡„ ์›์น™)๋ฅผ ์ค€์ˆ˜ํ•˜๋ฉฐ ์ƒˆ๋กœ์šด ์ „๋žต์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    ๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป ์ฝ”๋“œ๋กœ ์•Œ์•„๋ณด์ž

    ๋‹ค์–‘ํ•œ ๊ฒฐ์ œ ๋ฐฉ์‹์„ ๊ตฌํ˜„ํ•˜๋Š” ์ „๋žต ํŒจํ„ด ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด์ž.

    // 1. ์ „๋žต ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜
    interface PaymentStrategy {
        void pay(int amount);
    }
    
    // 2. ๊ตฌ์ฒด์ ์ธ ์ „๋žต ํด๋ž˜์Šค๋“ค
    class CreditCardPayment implements PaymentStrategy {
        private String cardNumber;
        private String name;
    
        public CreditCardPayment(String cardNumber, String name) {
            this.cardNumber = cardNumber;
            this.name = name;
        }
    
        @Override
        public void pay(int amount) {
            System.out.println(amount + "์›์„ ์‹ ์šฉ์นด๋“œ(" + cardNumber + ")๋กœ ๊ฒฐ์ œํ–ˆ์Šต๋‹ˆ๋‹ค.");
        }
    }
    
    class NaverPayPayment implements PaymentStrategy {
        private String email;
    
        public NaverPayPayment(String email) {
            this.email = email;
        }
    
        @Override
        public void pay(int amount) {
            System.out.println(amount + "์›์„ ๋„ค์ด๋ฒ„ํŽ˜์ด(" + email + ")๋กœ ๊ฒฐ์ œํ–ˆ์Šต๋‹ˆ๋‹ค.");
        }
    }
    
    class BankTransferPayment implements PaymentStrategy {
        private String bankAccount;
    
        public BankTransferPayment(String bankAccount) {
            this.bankAccount = bankAccount;
        }
    
        @Override
        public void pay(int amount) {
            System.out.println(amount + "์›์„ ๊ณ„์ขŒ์ด์ฒด(" + bankAccount + ")๋กœ ๊ฒฐ์ œํ–ˆ์Šต๋‹ˆ๋‹ค.");
        }
    }
    
    // 3. ์ปจํ…์ŠคํŠธ ํด๋ž˜์Šค
    class ShoppingCart {
        private PaymentStrategy paymentStrategy;
    
        // ์ „๋žต ์„ค์ •
        public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
            this.paymentStrategy = paymentStrategy;
        }
    
        // ๊ฒฐ์ œ ์‹คํ–‰
        public void checkout(int amount) {
            if (paymentStrategy == null) {
                System.out.println("๊ฒฐ์ œ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”.");
                return;
            }
            paymentStrategy.pay(amount);
        }
    }
    
    // ์‹คํ–‰ ์ฝ”๋“œ
    public class StrategyPatternExample {
        public static void main(String[] args) {
            ShoppingCart cart = new ShoppingCart();
    
            // ์‹ ์šฉ์นด๋“œ ๊ฒฐ์ œ
            System.out.println("๐Ÿ’ณ ์‹ ์šฉ์นด๋“œ ๊ฒฐ์ œ");
            cart.setPaymentStrategy(new CreditCardPayment("1234-5678-9012-3456", "ํ™๊ธธ๋™"));
            cart.checkout(80000);
    
            // ๋„ค์ด๋ฒ„ํŽ˜์ด ๊ฒฐ์ œ
            System.out.println("\n๐ŸŸข ๋„ค์ด๋ฒ„ํŽ˜์ด ๊ฒฐ์ œ");
            cart.setPaymentStrategy(new NaverPayPayment("user@example.com"));
            cart.checkout(50000);
    
            // ๊ณ„์ขŒ์ด์ฒด ๊ฒฐ์ œ
            System.out.println("\n๐Ÿฆ ๊ณ„์ขŒ์ด์ฒด ๊ฒฐ์ œ");
            cart.setPaymentStrategy(new BankTransferPayment("123-456-789"));
            cart.checkout(100000);
        }
    }
    • PaymentStrategy ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋ชจ๋“  ๊ฒฐ์ œ ์ „๋žต์˜ ๊ณตํ†ต ์ธํ„ฐํŽ˜์ด์Šค ์—ญํ• ์„ ํ•œ๋‹ค.
    • ๊ตฌ์ฒด์ ์ธ ์ „๋žต ํด๋ž˜์Šค๋“ค(CreditCardPayment, NaverPayPayment, BankTransferPayment)์ด ๊ฐ๊ฐ์˜ ๊ฒฐ์ œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ตฌํ˜„ํ•œ๋‹ค.
    • ShoppingCart๋Š” ์ปจํ…์ŠคํŠธ ํด๋ž˜์Šค๋กœ, ์„ค์ •๋œ ์ „๋žต์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฐ์ œ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ์‹คํ–‰ ์ค‘์— ๋‹ค์–‘ํ•œ ๊ฒฐ์ œ ๋ฐฉ์‹์œผ๋กœ ๊ต์ฒด ๊ฐ€๋Šฅํ•˜๋‹ค.

     

     

     

    โ˜˜๏ธ ์žฅ/๋‹จ์ 

    โœ… ์žฅ์ 

    1. ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ต์ฒด ์šฉ์ด์„ฑ
      • ์‹คํ–‰ ์ค‘์— ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ์–ด ์œ ์—ฐ์„ฑ์ด ๋†’๋‹ค.
      • ์‚ฌ์šฉ์ž ์š”๊ตฌ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์ „๋žต์œผ๋กœ ์‰ฝ๊ฒŒ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.
    2. ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ๋ฐ ์ค‘๋ณต ์ œ๊ฑฐ
      • ๊ฐ ์ „๋žต์€ ๋…๋ฆฝ์ ์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
      • ์œ ์‚ฌํ•œ ๊ธฐ๋Šฅ์„ ์—ฌ๋Ÿฌ ํด๋ž˜์Šค์—์„œ ์ค‘๋ณต ๊ตฌํ˜„ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
    3. ์ปจํ…์ŠคํŠธ์™€ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ถ„๋ฆฌ
      • ์ปจํ…์ŠคํŠธ(ShoppingCart)๋Š” ๊ตฌ์ฒด์ ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ชฐ๋ผ๋„ ๋˜๋ฏ€๋กœ ๊ฒฐํ•ฉ๋„๊ฐ€ ๋‚ฎ์•„์ง„๋‹ค.
      • ์ด๋Š” ์ฝ”๋“œ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ์„ ๋†’์ธ๋‹ค.
    4. ์ƒˆ๋กœ์šด ์ „๋žต ์ถ”๊ฐ€ ์šฉ์ด
      • ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด ์ „๋žต์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค(OCP ์ค€์ˆ˜).
      • ์˜ˆ๋ฅผ ๋“ค์–ด, KakaoPayPayment ๊ฐ™์€ ์ƒˆ๋กœ์šด ๊ฒฐ์ œ ๋ฐฉ์‹์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    โŒ ๋‹จ์ 

    1. ํด๋ž˜์Šค ์ˆ˜ ์ฆ๊ฐ€
      • ๊ฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜๋งˆ๋‹ค ๋ณ„๋„์˜ ํด๋ž˜์Šค๊ฐ€ ํ•„์š”ํ•˜๋ฏ€๋กœ ์ „์ฒด ํด๋ž˜์Šค ์ˆ˜๊ฐ€ ๋งŽ์•„์งˆ ์ˆ˜ ์žˆ๋‹ค.
      • ์ž‘์€ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์˜คํžˆ๋ ค ๋ณต์žก์„ฑ์„ ์ฆ๊ฐ€์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
    2. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ „๋žต์„ ์•Œ์•„์•ผ ํ•จ
      • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ ์ ˆํ•œ ์ „๋žต์„ ์„ ํƒํ•˜๊ณ  ์„ค์ •ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์ „๋žต์— ๋Œ€ํ•œ ์ง€์‹์ด ํ•„์š”ํ•˜๋‹ค.
      • ์ด๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ๋ณต์žก์„ฑ์„ ์ฆ๊ฐ€์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
    3. ๋ฐ์ดํ„ฐ ๊ณต์œ  ๋ฌธ์ œ
      • ์—ฌ๋Ÿฌ ์ „๋žต ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต์œ ํ•ด์•ผ ํ•  ๊ฒฝ์šฐ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค.
      • ์ปจํ…์ŠคํŠธ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๊ฑฐ๋‚˜ ์ „๋žต ํด๋ž˜์Šค ๊ฐ„์˜ ํ†ต์‹ ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋‹ค.
    4. ๋ฏธ์‚ฌ์šฉ ์ „๋žต์œผ๋กœ ์ธํ•œ ์˜ค๋ฒ„ํ—ค๋“œ
      • ๋ชจ๋“  ์ „๋žต์„ ๋ฏธ๋ฆฌ ๊ตฌํ˜„ํ•ด ๋†“์œผ๋ฉด ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ „๋žต๋„ ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋“œ๋œ๋‹ค.
      • ์ด๋Š” ๋ฆฌ์†Œ์Šค ๋‚ญ๋น„๋ฅผ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    ๐Ÿ“Œ ์ •๋ฆฌ

    ์ „๋žต ํŒจํ„ด์€ ํ–‰์œ„๋ฅผ ์บก์Аํ™”ํ•˜๊ณ  ๋Ÿฐํƒ€์ž„์— ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ์œ ์—ฐํ•œ ๋””์ž์ธ ํŒจํ„ด์ด๋‹ค.

    ์ด ํŒจํ„ด์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋Š” ์ปจํ…์ŠคํŠธ์™€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ตฌํ˜„์„ ๋ถ„๋ฆฌํ•จ์œผ๋กœ์จ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”๊ณ  ํ™•์žฅ์„ฑ์„ ๋†’์—ฌ์ค€๋‹ค. ๋‹ค์–‘ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ํ•„์š”ํ•˜๊ณ  ์‹คํ–‰ ์ค‘์— ์ด๋ฅผ ๊ต์ฒดํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ ํŠนํžˆ ์œ ์šฉํ•˜์ง€๋งŒ, ํด๋ž˜์Šค ์ˆ˜ ์ฆ๊ฐ€์™€ ํด๋ผ์ด์–ธํŠธ์˜ ์ฑ…์ž„ ์ฆ๊ฐ€๋ผ๋Š” ๋‹จ์ ๋„ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค.

     

    โœ… ์–ธ์ œ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์„๊นŒ?

    • ๋น„์Šทํ•œ ๊ธฐ๋Šฅ์„ ํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ
    • ๋Ÿฐํƒ€์ž„์— ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋™์ ์œผ๋กœ ๊ต์ฒดํ•ด์•ผ ํ•  ๋•Œ
    • ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์„ธ๋ถ€ ๊ตฌํ˜„์„ ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ์ˆจ๊ธฐ๊ณ  ์‹ถ์„ ๋•Œ
    • ์กฐ๊ฑด๋ฌธ์ด ๋งŽ๊ณ  ๋ณต์žกํ•ด์ง€๋Š” ๊ฒฝ์šฐ(if-else ๋˜๋Š” switch-case๊ฐ€ ๋งŽ์„ ๋•Œ)

    โŒ ์–ธ์ œ ํ”ผํ•ด์•ผ ํ• ๊นŒ?

    • ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๊ฑฐ์˜ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์„ ๋•Œ
    • ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๋‹จ์ˆœํ•˜์—ฌ ์บก์Аํ™”ํ•  ํ•„์š”๊ฐ€ ์—†์„ ๋•Œ
    • ์ „๋žต์˜ ์ˆ˜๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์•„์„œ ๊ด€๋ฆฌ๊ฐ€ ๋ณต์žกํ•ด์งˆ ๋•Œ
    • ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ๊ฒฝ์šฐ(์ถ”๊ฐ€์ ์ธ ๊ฐ์ฒด ์ƒ์„ฑ์œผ๋กœ ์ธํ•œ ์˜ค๋ฒ„ํ—ค๋“œ)

     

    ๐Ÿ“Š ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด๊ณผ ๋น„๊ต

    ํ•ญ๋ชฉ ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด ์ „๋žต ํŒจํ„ด
    ๊ตฌํ˜„ ๋ฐฉ์‹ ์ƒ์†์„ ํ†ตํ•ด ๊ตฌํ˜„ ํ•ฉ์„ฑ(composition)์„ ํ†ตํ•ด ๊ตฌํ˜„
    ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ต์ฒด ์ปดํŒŒ์ผ ํƒ€์ž„์— ๊ฒฐ์ • ๋Ÿฐํƒ€์ž„์— ๋™์ ์œผ๋กœ ๊ต์ฒด ๊ฐ€๋Šฅ
    ๊ตฌ์กฐ ์ƒ์œ„ ํด๋ž˜์Šค๊ฐ€ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ณจ๊ฒฉ ์ •์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์บก์Аํ™”
    ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ์ƒ์œ„ ํด๋ž˜์Šค ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํด๋ž˜์Šค ์žฌ์‚ฌ์šฉ
    ์ฃผ์š” ๊ด€๊ณ„ ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„(is-a) ์ธํ„ฐํŽ˜์ด์Šค-๊ตฌํ˜„ ๊ด€๊ณ„(has-a)
    ์œ ์—ฐ์„ฑ ์ƒ๋Œ€์ ์œผ๋กœ ๋‚ฎ์Œ ๋†’์Œ(์‹คํ–‰ ์ค‘ ๊ต์ฒด ๊ฐ€๋Šฅ)
    ํ™•์žฅ์„ฑ ํ•˜์œ„ ํด๋ž˜์Šค ์ถ”๊ฐ€๋กœ ํ™•์žฅ ์ƒˆ๋กœ์šด ์ „๋žต ํด๋ž˜์Šค ์ถ”๊ฐ€๋กœ ํ™•์žฅ

     

     

    ๐Ÿ“‹ ์ฐธ๊ณ