전략(Strategy) 패턴이란?
전략 패턴이란 객체 지향 디자인 패턴 중 하나로 알고리즘을 정의하고 각각을 캡슐화하여 그들을 상호 교체 가능하게 만드는 패턴입니다.
객체가 할 수 있는 행위를 각각 정의하여 입력 받은 타입에 대한 처리를 각각의 파일에서 동적으로 수행합니다.
주요 구성 요소
- 전략 인터페이스(Strategy Interface) : 모든 구체적인 전략이 구현해야하는 인터페이스 입니다.
interface TravelStrategy {
travel(): string;
}
- 구체적인 전략(Concrete Strategies) : 전략 인터페이스를 구현하는 여러 클래스들은 실제 로직이나 알고리즘을 정의합니다.
class WalkingStrategy implements TravelStrategy {
travel(): string {
return "걸어가는 중!";
}
}
class BikeStrategy implements TravelStrategy {
travel(): string {
return "자전거 타고 가는 중!";
}
}
class BusStrategy implements TravelStrategy {
travel(): string {
return "버스 타고 가는 중!";
}
}
- 컨텍스트(Context) : 전략 객체를 구성하며 전략을 통해 정의된 알고리즘을 실행합니다.
class Traveler {
private strategy: TravelStrategy;
constructor(strategy: TravelStrategy) {
this.strategy = strategy;
}
setTravelStrategy(strategy: TravelStrategy) {
this.strategy = strategy;
}
startJourney(): string {
return this.strategy.travel();
}
}
const dongbok = new Traveler(new WalkingStrategy());
console.log(john.startJourney()); // "걸어가는 중!"
dongbok.setTravelStrategy(new BikeStrategy());
console.log(john.startJourney()); // "자전거 타고 가는 중!!"
dongbok.setTravelStrategy(new BusStrategy());
console.log(john.startJourney()); // "버스 타고 가는 중!"
전략 패턴을 활용한 로그인 구현
- 실제 로그인 로직은 없으며 전략 패턴을 실습하고자 임의 객체를 만들어 실습
- interface/login.request.ts : 유저 아이디와 패스워드를 담을 객체 구조 정의
- service/user.service.ts : 로그인 클래스 정의
- strategy/Authenticator.ts : 요청을 받았을때 요청에 대한 성공 실패 여부를 검증 해주는 객체 구조 정의
- strategy/email.strategy.ts : email 형식으로 로그인을 요청했을때
- strategy/google.strategy.ts : google 로그인 요청했을때
- strategy/kakao.strategy.ts : kakao 로그인 요청했을때
- strategy/strategy.ts : email, google, kakao 로그인 로직을 하나로 묶음
- user.controller.ts : 사용자가 로그인 요청을 하면 서비스를 수행할 클래스 정의
- index.ts : 위에서 정의된 전략 패턴을 생성자로 받아온 뒤 로그인 작업 수행
user/interface/login.request.ts
// 유저 정보 객체 구조 정의
export interface UserParams {
email: string;
password: string;
}
user/service/user.service.ts
import Strategy from "../strategy/strategy";
import { UserParams } from "../interfaces/login.request";
import { AuthenticatonResponse } from "../strategy/Authenticator";
// 유저 서비스 로직 클래스 정의
class UserService {
// 전략패턴 유저 로그인 서비스 로직 객체
// 이메일, 카카오, 구글 세가지 로그인 로직을 사용
constructor(private readonly strategy: Strategy) {}
async login(
type: string,
credentials: UserParams
): Promise<AuthenticatonResponse> {
const result = await this.strategy.login(type, credentials);
return result;
}
}
export default UserService;
user/strategy/Authenticator.ts
import { UserParams } from "../interfaces/login.request";
// 응답 받았을때 객체의 구조 정의
export interface AuthenticatonResponse {
success: boolean;
message?: string; // 옵셔널 체이닝을 사용하여 없어도 사용가능
}
// 검증 객체 구조 정의
export interface Authenticator {
// 로그인 검증 함수 구조 선언
authentcate(credentials: UserParams): Promise<AuthenticatonResponse>;
}
user/strategy/email.strategy.ts
import { UserParams } from "../interfaces/login.request";
import { AuthenticatonResponse, Authenticator } from "./Authenticator";
// email 형식으로 로그인 시도했을때
export class EmailAuthenticator implements Authenticator {
async authentcate(credentials: UserParams): Promise<AuthenticatonResponse> {
// email 로그인 로직
console.log("email login success");
return { success: true };
}
}
user/strategy/google.strategy.ts
import { UserParams } from "../interfaces/login.request";
import { AuthenticatonResponse, Authenticator } from "./Authenticator";
// 구글 계정으로 로그인 시도 했을때
export class GoogleAuthenticator implements Authenticator {
async authentcate(credentials: UserParams): Promise<AuthenticatonResponse> {
// 구글 로그인 로직 작성);
return { success: true };
}
}
user/strategy/kakao.strategy.ts
import { UserParams } from "../interfaces/login.request";
import { AuthenticatonResponse, Authenticator } from "./Authenticator";
// 카카오 계정으로 로그인 시도 했을때
export class KakaoAuthenticator implements Authenticator {
async authentcate(credentials: UserParams): Promise<AuthenticatonResponse> {
// 카카오 로그인 로직
console.log("kakao login success");
return { success: true };
}
}
user/strategy/strategy.ts
import { UserParams } from "../interfaces/login.request";
import { AuthenticatonResponse, Authenticator } from "./Authenticator";
// 3개의 로그인 로직을 하나로 묶음
// 전략 패턴 객체 구조 정의
interface IStrategy {
// key를 문자열로 지정
[key: string]: Authenticator;
}
// 서비스 로직들을 가질 객체 구조 정의
class Strategy {
private strategy: IStrategy = {};
// 서비스 로직을 객체에 추가할 함수
public set(key: string, authenticate: Authenticator) {
// key 값을 받고 서비스 로직 추가
this.strategy[key] = authenticate;
}
public async login(
type: string,
credentials: UserParams
): Promise<AuthenticatonResponse> {
const result = await this.strategy[type].authentcate(credentials);
return result;
}
}
export default Strategy;
user/user.controller.ts
import { UserParams } from "./interfaces/login.request";
import UserService from "./service/user.service";
// 사용자 서비스 로직 클래스 정의
class UserController {
constructor(private readonly userService: UserService) {}
// 로그인
// /login/:type으로 요청이 들어왔다면
signin(type: string) {
console.log("실행 순서 1 : UserController.signin");
// req.body에서 유저의 정보를 받아옴(실습 환경에서는 임시 객체 사용)
const loginParams: UserParams = {
email: "db@google.com",
password: "1234",
};
this.userService.login(type, loginParams);
}
// 회원가입
// /signup
signup() {}
}
export default UserController;
user/index.ts
import Strategy from "./strategy/strategy";
import UserService from "./service/user.service";
import { GoogleAuthenticator } from "./strategy/google.strategy";
import { KakaoAuthenticator } from "./strategy/kakao.strategy";
import { EmailAuthenticator } from "./strategy/email.strategy";
import UserController from "./user.controller";
// 전략 패턴 객체 생성
const strategy = new Strategy(); // { strategy: {},set(), login() }
strategy.set("email", new EmailAuthenticator()); // { strategy: { EmailAuthenticator { authentcate }},set(), login() }
strategy.set("kakao", new KakaoAuthenticator()); // { strategy: { EmailAuthenticator { authentcate }},{ KakaoAuthenticator { authentcate }},set(), login() }
strategy.set("google", new GoogleAuthenticator()); // { strategy: { EmailAuthenticator { authentcate }},{ KakaoAuthenticator { authentcate }},{ GoogleAuthenticator { authentcate }},set(), login() }
// 완성된 객체를 유저 서비스 클래스 생성자의 매개변수로 전달 및 유저 서비스 객체 생성
const userService = new UserService(strategy);
// 유저 로그인 로직 클래스 생성 및 유저 서비스 로직 객체 생성자 매개변수로 전달
const userController = new UserController(userService);
userController.signin("google");
728x90
'TypeScript' 카테고리의 다른 글
[TypeScript] Class와 Interface 알아보기 (0) | 2023.08.31 |
---|---|
[TypeScript] TypeScript 기본 문법 알아보기 (0) | 2023.08.31 |
[TypeScript] TypeScript 알아보기 (0) | 2023.08.30 |