[디자인패턴] 전략 패턴, Strategy Pattern

sunny·2023년 3월 5일
0

디자인 패턴

목록 보기
4/11
post-thumbnail

전략 패턴, Strategy Pattern


전략 패턴이란?

객체의 행위를 바꾸고 싶은 경우 직접 수정하지 않고 전략이라고 부르는 캡슐화한 알고리즘 을 컨텍스트 안에서 바꿔주면서 상호 교체가 가능하게 만드는 패턴

  • 객체의 행위를 동적으로 바꾸고 싶은 경우 직접 행위를 수정하지 않고 전략이라고 부르는 캡슐화한 알고리즘을 바꿔주기만 함으로써 행위를 유연하게 확장하는 방법
  • 언제 사용될까?
    • if-else 코드 블럭으로 구성되어 있는데, 모든 코드가 비슷한 기능을 수행하는 경우
    • 완벽히 동일한 기능을 수행하지만, 요구 성능에 따라 다른 알고리즘을 선택해야 하는 경우

전략 패턴의 구성 요소

https://user-images.githubusercontent.com/88873302/222950665-2e480714-ee8f-42b5-8f4a-0e5abe593656.png

  • 전략 (strategy) : 구체화된 여러 알고리즘들의 추상화로써, 변하는 부분들 담당
  • 전략 콘크리트 (concrete strategy) : 여러 알고리즘의 실제 구현
  • 전략 사용자 (context) : 전략을 사용하는 프로그램의 흐름으로, 변하지 않는 것
  • 전략 제공자 (client) : 전략 사용자에게 실제 전략으로 사용할 전략 콘크리트 클래스를 주입하는 역할

전략 패턴의 장점 & 단점

장점

  • 전략 사용자 (context)의 코드 변경 없이 새로운 전략을 추가할 수 있다.
  • 확장 가능성
  • 런타임에 전략을 변경시킬 수 있다.

단점

  • 어떤 전략 콘트리트에서는 사용하지 않는 메서드들 역시 전략 인터페이스에 정의해 주어야 하기 때문에 전략을 추상화한 인터페이스가 효율적이 못할 수 있다.

예제 코드

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

// strategy & concrete strategy
interface PaymentStrategy {
    public void pay(int amount);
}

class KAKAOCardStrategy implements PaymentStrategy {
    private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;

    public KAKAOCardStrategy (String nm, String ccNum, String cvv, String expiryDate) {
        this.name = nm;
        this.cardNumber = ccNum;
        this.cvv = cvv;
        this.dateOfExpiry = expiryDate;
    }

    @Override
    public void pay (int amount) {
        System.out.println(amount + " paid using KAKAOCard.");
    }
}

class LUNACardStrategy implements PaymentStrategy {
    private String emailId;
    private String password;

    public LUNACardStrategy (String email, String pwd) {
        this.emailId = email;
        this.password = pwd;
    }

    @Override
    public void pay (int amount) {
        System.out.println(amount + " paid using LUNACard.");
    }
}

class Item {
    private String name;
    private int price;
    public Item(String name, int cost) {
        this.name = name;
        this.price = cost;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }
}

class ShoppingCart {
    List<Item> items;

    public ShoppingCart() {
        this.items = new ArrayList<Item>();
    }

    public void addItem(Item item) {
        this.items.add(item);
    }

    public void removeItem(Item item) {
        this.items.remove(item);
    }

    public int calculateTotal() {
        int sum = 0;
        for (Item item : items) {
            sum += item.getPrice();
        }
        return sum;
    }
		// context
    public void pay(PaymentStrategy paymentMethod) {
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}

public class Demo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        Item A = new Item("kundolA", 100);
        Item B = new Item("kundolB", 300);

        cart.addItem(A);
        cart.addItem(B);
				// client
        // pay by LUNACard
        cart.pay(new LUNACardStrategy("kundol@example.com", "abcde"));

        // pay by KAKAOCard
        cart.pay(new KAKAOCardStrategy("Amy", "123456", "123", "12/01"));
    }
}

💡 결제를 하는 pay() 함수에는 KAKAOCard 를 사용할지 LUNACard 를 사용할지에 대한 어떠한 로직도 존재하지 않는다. pay() 함수를 포함한 PaymentStrategy 라는 인터페이스를 KAKAOCardStrategyLUNACardStrategy 클래스가 각각 상속 받아 그 안에서 각자 pay() 함수를 처리한다.

👉 추후에 다른 카드들이 추가되더라도 pay() 함수를 수정할 필요 없다


참고 자료

  • 면접을 위한 CS 전공지식 노트

0개의 댓글

관련 채용 정보