템플릿은 상위타입에서 틀이 되는 추상메서드를 제공하고, 하위에서 그 추상메서드를 구현함으로써 동적 실행시 하위 타입에 맞게 실행되게 하는 구조
틀을 제공한다는 관점에서 전략패턴과 유사하나, 하나의 객체타입이 대체되는 부분과 메서드를 오버라이딩하여 실행하는 관점의 차이가 있다.
그래서 템플릿은 메서드 내의 알고리즘 순서에 의해 완성되고, 전략은 객체타입의 변경에 따라 완전 내용이 전반적으로 모든게 바뀌는 느낌
예제
// configTemplate.jsconstfs=require('fs');constobjectPath=require('object-path');classConfigTemplate {read(file) {console.log(`Deserializing from ${file}`);this.data =this._deserialize(fs.readFileSync(file,'utf-8')); }save(file) {console.log(`Serializing to ${file}`);fs.writeFileSync(file,this._serialize(this.data)); }get(path) {returnobjectPath.get(this.data, path); }set(path, value) {returnobjectPath.set(this.data, path, value); }_serialize() {thrownewError('_serialize() must be implemented'); }_deserialize() {thrownewError('_deserialize() must be implemented'); }}module.exports= ConfigTemplate;// jsonConfig.js -> JSON을 처리해주는 하위타입constutil=require('util');constConfigTemplate=require('./configTemplate');classJsonConfigextendsConfigTemplate {_deserialize(data) {returnJSON.parse(data); }_serialize(data) {returnJSON.stringify(data,null,' '); }}module.exports= JsonConfig;// iniConfig.js -> ini으로 처리해주는 하위타입constConfigTemplate=require('./configTemplate');constini=require('ini');classIniConfigextendsConfigTemplate {_serialize(data) {returnini.stringify(data); }_deserialize(data) {returnini.parse(data); }}module.exports= IniConfig;// test.jsconstJsonConfig=require('./jsonConfig');constjsonConfig=newJsonConfig();constIniConfig=require('./iniConfig');constiniConfig=newIniConfig();jsonConfig.read('samples/conf.json');jsonConfig.set('nodejs','design patterns');jsonConfig.save('samples/conf_mod.json');iniConfig.read('samples/conf.ini');iniConfig.set('nodejs','design patterns');iniConfig.save('samples/conf_mod.ini');
6.9 미들웨어(Middleware)
저수준 추상화 -> OS, API, 네트워크통신, 메모리 관리 등
미들웨어 예 -> CORBA, ENterprise Service Bus, Spring, JBoss, Apache Web Server 등
미들웨어 : 일반적으로 하위서비스와 어플리케이션사이의 인터페이스, 연계, 접착제 같은 모든 SW 계층으로 정의 가능
6.9.1 미들웨어로서의 Express
Express에서 미들웨어 -> 파이프라인에서 구성되고 들어오는 HTTP 요청 및 응답의 처리
// req : 요청, res : 응답, next : 미들웨어 (트리거 할때 콜백)function (req,res,next) { }
6.9.2 패턴으로서의 미들웨어
Intercepting Filter 패턴과 Chain of Responsibility 패턴의 Node.js화
스트림, 파이프라인 이라고 할 수도 있음
모든 종류의 데이터에 대한 전처리 및 후처리를 수행
함수형태로 처리 단위(processing unit), 필터(filter) 및 핸들러(handler) 집합이 비동기 시퀀스의 형태로 연결된 특정 패턴
express -> use함수 : 미들웨어 등록 -> 데이터처리는 비동기 순차실행의 흐름
6.9.3 MQ 용 미들웨어 프레임워크 만들기
메시지큐, 메시징라이브러리를 중심으로 미들웨어 프레임워크를 구축함으로써 패턴을 설명.
분산시스템 데이터 처리에 활용됨
데이터의 전처리 및 후처리 추상화하는 미들웨어 인프라 구축
// server.js// const zmq = require('zeromq');constzmq=require('zmq');constZmqMiddlewareManager=require('./zmqMiddlewareManager');constjsonMiddleware=require('./jsonMiddleware');constsocket=zmq.socket('req');// const socket = zmq.Push;socket.bind('tcp://127.0.0.1:5000');constzmqm=newZmqMiddlewareManager(socket);zmqm.use(jsonMiddleware.json());zmqm.use({inbound:function (message, next) {console.log('Received: ',message.data);if (message.data.action ==='ping') {this.send({action:'pong', echo:message.data.echo}); }next(); }});// zmqMiddlewareManager.jsmodule.exports=classZmqMiddlewareManager {constructor(socket) {this.socket = socket;this.inboundMiddleware = []; // 들어오는 메시지 처리 (수신메시지)this.outboundMiddleware = []; // 나가는 메시지 처리 (발신메시지)socket.on('message', message => {this.executeMiddleware(this.inboundMiddleware, { data: message }); });// console.log(this.socket.send);; }// 새로운 메시지가 소켓을 통해 전송될 때, 미들웨어 역할send(data) {constmessage= { data };// 데이터 보내기, 아웃바운드 처리this.executeMiddleware(this.outboundMiddleware, message, () => {this.socket.send(message.data); }); }// 미들웨어 형식에 따른 추가use(middleware) {if (middleware.inbound) {this.inboundMiddleware.push(middleware.inbound); // 배열 맨 뒤에 추가 }if (middleware.outbound) {this.outboundMiddleware.unshift(middleware.outbound); // 배열 맨 앞에 추가 } }// 미들웨어가 처리executeMiddleware(middleware, arg, finish) {functioniterator(index) {if (index ===middleware.length) {return finish &&finish(); } middleware[index].call(this, arg, err => {if (err) {returnconsole.log('There was an error : ',err.message); }iterator.call(this,++index); }); }iterator.call(this,0); }};// jsonMiddleware.jsmodule.exports.json= () => {return {inbound:function (message, next) {message.data =JSON.parse(message.data.toString()); // 수신 데이터 Buffer -> JSONnext(); },outbound:function (message, next) {message.data =newBuffer(JSON.stringify(message.data)); // 데이터 송신 : JSON -> Buffer } }};// client.js constzmq=require('zmq');constZmqMiddlewareManager=require('./zmqMiddlewareManager');constjsonMiddleware=require('./jsonMiddleware');constrequest=zmq.socket('req');request.connect('tcp://127.0.0.1:5000');constzmqm=newZmqMiddlewareManager(request);zmqm.use(jsonMiddleware());zmqm.use({inboud:function (message, next) {console.log('Echoed back : ',message.data);next(); }});setInterval(() => {zmqm.send({action:'ping', echo:Date.now()})});
6.9.4 Koa에서 제너레이터를 사용한 미들웨어
미들웨어 패턴을 많이 사용하는 웹프레임워크 KoaKoa : 콜백 사용 대신 제너레이터 함수를 사용하는 미들웨어 패턴을 구현 인바운드(다운스트림), 아웃바운드(업스트림)