컴퓨터 공학 & 통신

[개념 정리/디자인 패턴] 행동 패턴 - 전략 패턴

왈왈디 2023. 7. 5. 13:57
728x90

전략 패턴

전략 패턴이란 전략이라고 부르는 캡슐화한 알고리즘

컨텍스트* 안에서 바꿔주면서

상호 교체가 가능하게 만드는 디자인 패턴이다. 

 

아래는 자바로 로그인의 전략 패턴을 구현한 예시 코드이다.

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

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;
    }
    
    public void pay(PaymentStrategy paymentMethod){
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}

public class HelloWorld{
    public static void main(String []args){
        ShoppingCart cart = new ShoppingCart();
        
        Item A = new Item("newItem",1500);
        Item B = new Item("goodItem",3000);
        
        cart.addItem(A);
        cart.addItem(B);
        
        // pay by LUNACard
        cart.pay(new LUNACardStrategy("walwal@example.com", "walwalddd"));
        
        // pay by KAKAOBank
        cart.pay(new KAKAOCardStrategy("Ju hongchul", "123456789", "123", "12/01"));
    }
}

/*
4500 paid using LUNACard.
4500 paid using KAKAOCard.
*/

 

대표적으로 자바스크립트의 로그인 라이브러리인 passport.js가 있다.

전략을 캡슐화하여 매개변수로 넣어 구현하는 방식이다.

 

아래는 자바스크립트의 passport.js의 사용 예시 코드이다.

var passport = require('passport')
	, LocalStrategy = require('passport-local').Strategy;

passport.use(new LocalStrategy(
	function(username, password, done) {
		User.findOne({ username: username }, function (err, user){
			if (err) { return done(err); }
			
            if (!user) {
				return done(null, false, { message: 'Incorrect username.' });
			}
			
            if (!user.validPassword(password)) {
				return done(null, false, { message: 'Incorrect password.' });
			}
            
			return done(null, user);
		});
	}
));

 

전략 패턴 VS 의존성 주입(DI)

전략 패턴의존성 주입 둘 다 무언가를 쉽게 교체하기 위한 디자인 패턴이라는 공통점이 있다.

그러나 아래와 같은 차이가 있다.

  • 전략 패턴: 어떠한 동일한 행동 계약을 기반으로 다양한 구현이 명시되어 있는 인터페이스를 만드는 것을 포함한다.
  • 의존성 주입: 단지 일부 동작을 구현하고 의존성을 주입하기만 하는 패턴이다.

 

컨텍스트

컨텍스트는 2가지 뜻으로 쓰인다.

  1. 어떤 종류의 상태, 환경을 캡슐화한 것
  2. 작업이 중단되고 나중에 같은 지점에서 계속될 수 있도록 저장하는 최소 데이터의 집합 (e.g., 컨텍스트 스위칭)

컨텍스트는 크게 contextcontextual information 두 가지로 나뉘어진다.

아래는 context와 contextual information에 관한 두 가지 예시이다.

  1. 병원에 가서 이름주민등록번호 앞자리를 말한다면, 병원에 방문하는 context에서 이름과 주민등록번호라는 contextual information을 전달한 것이다.
  2. HTTP 요청을 보내는 context에서 HTTP Headercontextual information이다.

이러한 이론을 기반으로 한 대표적인 예시로는 React.js에서 전역적으로 상태값을 관리하는 context API가 있다.

아래는 React에서 context API를 통해 전역적으로 static contextType을 통해 상태 관리를 하는 코드이다.

const ThemeContext = React.createContext('light');

class App extends React.Component {
	render() {
		return (
			<ThemeContext.Provider value="dark">
				<Toolbar />
			</ThemeContext.Provider>
		);
	}
}

function Toolbar() {
	return (
		<div>
			<ThemedButton />
		</div>
	);
}

class ThemedButton extends React.Component {
	static contextType = ThemeContext;
	render() {
		return <Button theme={this.context} />;
	}
}

 

참고: inflearn 강의 'CS 지식의 정석 - 큰돌'

728x90