이 글은 면접을 위한 CS 전공지식노트의 책을 읽고 학습 후 스터디 공유를 위한 글입니다.
정책패턴(Policy Pattern)이라고 부르기도 하며, **객체의 행위를 바꾸고 싶은 경우**
‘직접’ 수정하지 않고 **전략이라고 부르는 ‘캡슐화한 알고리즘’을 컨텍스트 안에서 바꿔주면서**
상호 교체가 가능하게 만드는 패턴
아래 코드는 물건을 담고 총액을 합산한 후 결제를 하는 시나리오다.
결제수단에 따른 전략을 각각의 클래스에 따로 추상화, 캡슐화 해놓고 결제를 하는 행위를 바꾸는 경우 그 캡슐화 한 알고리즘을 컨텍스트 안에서 바꿔준다.
interface PaymentStrategy {
pay(amount: number): void;
}
class KAKAOCardStrategy implements PaymentStrategy {
// 결제 수단에 따른 결제에 관련된 행위 즉, 전략을 구현한 클래스
private name: string;
private cardNumber: string;
private cvv: string;
private dateOfExpiry: string;
constructor(nm: string, ccNum: string, cvv: string, expiryDate: string) {
this.name = nm;
this.cardNumber = ccNum;
this.cvv = cvv;
this.dateOfExpiry = expiryDate;
}
public pay(amount: number): void {
console.log(amount + ' paid using KAKAOCard.');
}
}
class LUNACardStrategy implements PaymentStrategy {
// 결제 수단에 따른 결제에 관련된 행위 즉, 전략을 구현한 클래스
private emailId: string;
private password: string;
constructor(email: string, pwd: string) {
this.emailId = email;
this.password = pwd;
}
public pay(amount: number): void {
console.log(amount + ' paid using LUNACard.');
}
}
class Item {
private name: string;
private price: number;
constructor(name: string, cost: number) {
this.name = name;
this.price = cost;
}
public getName(): string {
return this.name;
}
public getPrice(): number {
return this.price;
}
}
class ShoppingCart {
private items: Array<Item>;
constructor() {
this.items = new Array<Item>();
}
public addItem(item: Item): void {
this.items.push(item);
}
public calculateTotal(): number {
const sum = this.items.reduce(
(total, crntItem) => total + crntItem.getPrice(),
0
);
return sum;
}
public pay(paymentMethod: PaymentStrategy){
let amount = this.calculateTotal();
paymentMethod.pay(amount);
}
}
let cart = new ShoppingCart();
let itemA = new Item("MacBook Pro", 300);
let itemB = new Item("MacBook Amateur", 150);
cart.addItem(itemA);
cart.addItem(itemB);
// pay by KAKAOCard
cart.pay(new KAKAOCardStrategy('변진상', "123123123", "123", "12/05"));
// => 450 paid using KAKAOCard.
// payby LUNACard
cart.pay(new LUNACardStrategy("진상@진상.진상", "1231231223"));
// => 450 paid using LUNACard.
// ShoppingCart 클래스의 인스턴스 내부 콘텍스트에 전략을 캡슐화한 인스턴스를 전달해 그 행위를 바꾼다.
Node.js 인증모듈 구현을 위한 미들웨어 라이브러리 → passport
서비스 내의 회원 가입된 아이디와 비밀번호를 이용해 인증하는 LocalStrategy 전략
과 페이스북, 네이버 등 외부 서비스를 기반으로 인증하는 OAuth 전략
등을 지원.
다음 코드에서 메서드에 전략을 매개 변수로 넣어 전략만 바꿔 인증하는 것을 확인할 수 있다.
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);
});
}
));
전략 패턴은 알고리즘의 동적인 교체와 다양한 변형이 필요한 경우에 유용