전략 (Strategy)
컨텍스트라는 객체를 활성화
=> 변수를 "전략" 이라는 별도의 상호 교환 가능한 객체로 추출
컨텍스트 : 알고리듬 제품군의 공통적인 로직 구현
전략 : 가변적인 부분을 구현, 컨텍스트가 값에 따라 다양한 요소에 따라 동작을 조정하도록 함
교체 가능한 부품이라고 생각하면 편함. 즉, 구조에따라 다른 전략(부품)으로 바꿔 사용
우려되는 사항을 분리하는데 도움
더 나은 유연성 제공
복잡한 조건문, 동일한 역할의 범위 내 다른 컴포넌트를 혼합 시 유용
Ex) 결제 시스템
- pay() 함수에서 if else 문을 사용하여 선택한 지불 옵션에 따라 작업을 완료
- 지불 처리를 사용자가 선택한 결제 게이트웨이 로직을 구현한 전략 객체에 위임함
전략 패턴 사용시 무제한의 결제 방법을 지원, 다른 객체가 결제 작업을 위임받아 처리하고 order 객체는 사용자, 구매항목 및 해당 항목의 가격같은 세부 정보만 관리하도록 범위를 제한
1. 여러 형식을 지원하는 환경설정 객체
Config 설정 객체, 매개변수에 접근하기 위한 간단한 인터페이스를 제공해야 함
영구적인 저장소를 사용해 구성을 가져오고 내보내는 방법 필요
JSON, INI, YAML 등의 다양한 형식 지원
전략패턴은 객체에서 동작이 변경될 부분을 직시 식별 할 수있음 => 설정 정보를 직렬화하거나 역 직렬화
// config.js
import {promises as fs} from 'fs';
import objectPath from 'object-path';
export class Config {
constructor (formatStrategy) {
// 생성자에 환경 설정 데이터 보관을 위해 data 인스턴스 변수 생성
this.data = {};
this.formatStrategy = formatStrategy;
}
get (configPath) {
// object-path 는 점 경로 표기법 사용해 환경설정 접근하는 set() get() 제공
return objectPath.get(this.data, configPath);
}
set(configPath,value) {
return objectPath.set(this.data, configPath,value);
}
async load(filePath) {
consoe.log(`Deserializing from ${filePath}`);
// 역/직렬화를 전략에 위임하는 곳
this.data = this.formatStrategy.deserialize(
await fs.readFile(filePath, 'utf-8');
)
}
async save (filePath) {
consoe.log(`Serialize to ${filePath}`);
await fs.wrtieFile(filePath,
this.formatStrategy.serialize(this.data));
}
}
하드코딩 되지 않음 => 주어진 전략에 따라 모든 파일형식을 수정하지 않고 적용 가능
이번에는 ini 형식의 환결설정 데이터 분석하고 직렬화 해봅시다.
import ini from 'ini';
export const iniStrategy = {
deserialize : data => ini.parse(data),
serialize : data => ini.stringify(data),
};
json 형식도 해보고요
export const jsonStragety = {
deserialize : data => JSON.parse(data),
serialize : data => JSON.stringify(data, null, ' '),
}
실제 사용은?
import { Config } from './config.js';
import { jsonStrategy, iniStragegy } from './strategies.js';
async function main() {
const iniConfig = new Config(iniStragegy);
await iniConfig.load('samples./conf.ini');
iniConfig.set('book.nodejs', 'design patterns');
await iniConfig.safe('samples/conf_mod.ini');
const jsonConfig = new Config(jsonStrategy);
await jsonConfig.load('sampls.conf.json');
jsonConfig.set('book.nodejs', 'design pattern');
await jsonConfig.save('samples/conf_mod.json');
}
main();
공통부분을 구현하는 하나의 Config 클래스만을 정의함
데이터 직렬화 및 역 직렬화를 위한 서로 다른 전략을사용하여 다른형식의 파일 지원 인스턴스 생성
다른 접근 방법
- 두가지 다른 전략 제품군 생성 : 한 형식을 읽고 다른 형식으로 저장
- 전략을 동적으로 선택 : Config 객체는 확장자 맵을 가지고 주어진 확장자에 따라 알맞은 알고리듬을 선택
어머 구현도 달라질거고, 간단한 형식으로 컨텍스트와 전략이 간단한 함수일 수 도 있음
function context(strategy) { ... }
!함수가 일급객체이고 완전한 조건을 갖춘 객체보다 많이 사용됨, 함수 과소평가 하지마셈
"변경 사이에서 변경되지 않는것" 이 패턴이 가진 사상, 구현은 어느정도 변경 될 수 있으나 패턴을 움직이게 하는 핵심 개념은 항상 동일합니다.
! 전략 패턴은 어댑터 패턴 구조와 유사, 둘 사이 상당한 차이 존재
어댑터 : 어댑터의 동작을 추가하지 않음, 다른 인터페이스와 호환을 위해 로직을 구현할수도 있으나 인터페이스만으로 제한
전략 : 컨텍스트와 전략 알고리듬이라는 두가지 다른 부분을 구현, 최종적 문제 해결을 위한 알고리듬을 구축하는것이 필수, 그리고 결합 필요
Example Packages
-Passport : 전략패턴을 사용하여 인증 프로세스 중 공통된 로직을 실제 인증단계와 같이 변경할 수있는 부분과 분리함
OAuth 방식 등으로 서로 다른 전략으로 인증 처리
'Javascript > Node.js' 카테고리의 다른 글
Template Pattern - 행위 디자인 패턴 (0) | 2022.02.09 |
---|---|
State Pattern - 행위 디자인 패턴 (0) | 2022.02.09 |
Adaptor Pattern - 구조적 설계 패턴 (0) | 2022.02.09 |
Decorator Pattern - 구조적 설계 디자인 (0) | 2022.02.09 |
Proxy Pattern - 구조적 설계 패턴 (0) | 2022.02.06 |
댓글