Mediator/Middleware 패턴
컴포넌트들이 서로 직접 통신하는 대신 중재자 역할을 하는 객체를 통하도록 한다. 중재가 객체가 요청을 받아 이를 필요로 하는 객체들에게 전달하는 것이다. 중재자는 보통 객체나 함수로 구현된다.
이 패턴은 공항에서 비행기의 동선을 관리하는 관제소에 비교할 수 있다. 비행기끼리 직접 통신하면 사고로 이어질 수 있겠지만 관제소에서 상황을 전달받아 통제를 하게 되면 서로 충돌 없이 안전하게 활주로를 이용할 수 있게 된다.
자바스크립트로 비행기를 조종할 일은 없겠지만. 종종 여러 객체들이 서로 데이터를 주고 받는 상황이 생기곤 한다. 컴포넌트가 많아질수록 통신의 횟수는 많아지며 점점 흐름을 파악하기 어려워 질 것이다.
객체끼리 서로 통신하게 하여 다대다의 관계를 이루게 하는 대신 객체의 요청들을 모두 중재자 객체에게 보낸다. 중재자는 이런 요청들을 처리하여 이를 필요로 하는 객체에게 전달한다.
실무에서 이 중재재 패턴이 적합한 곳은 채팅을 구현할 때 이다. 채팅 앱에서 사용자는 메시지를 직접 서로 주고 받지 않는다. 그 대신 채팅 서버에 메시지를 전송하고 서버가 각 사용자에게 메시지를 전달하는 형태이다.
class ChatRoom {
logMessage(user, message) {
const time = new Date()
const sender = user.getName()
console.log(`${time} [${sender}]: ${message}`)
}
}
class User {
constructor(name, chatroom) {
this.name = name
this.chatroom = chatroom
}
getName() {
return this.name
}
send(message) {
this.chatroom.logMessage(this, message)
}
}
위의 예제에서 사용자는 ChatRoom
과 연결되는 User
를 만들어낼 수 있고. 각 인스턴스는 send
메서드를 통해 다른 사용자에게 메시지를 전송할 수 있다.
사례 분석
Express.js는 많이 사용하는 웹 서버 프레임웍이다. 특정 라우팅 경로에 대해 콜백을 추가함으로써 요청을 처리할 수 있다.
'/'
경로를 요청했을 때 요청에 헤더를 추가해야 한다고 가정해 보자. 아래 예시와 같이 미들웨어를 추가하여 처리할 수 있다.
const app = require('express')()
app.use('/', (req, res, next) => {
req.headers['test-header'] = 1234
next()
})
next
함수는 요청-응답 사이클에 걸려있는 다음 콜백을 호출한다. 아래 그림과 같이 요청-응답 사이에 콜백 체인을 추가할 수 있다.
아래 에제에서는 위의 예시에서 헤더가 잘 추가되었는지 검사하는 미들웨어를 추가했다. 이전 콜백의 변경 사항을 다음 콜백에서 확인할 수 있는 것이다.
const app = require('express')()
app.use(
'/',
(req, res, next) => {
req.headers['test-header'] = 1234
next()
},
(req, res, next) => {
console.log(`Request has test header: ${!!req.headers['test-header']}`)
next()
}
)
아래 예시에서는 하나 이상의 함수를 추가하여 요청 객체를 추적하거나 수정하고 있다.
엔드포인트 '/'
가 호출될 때 마다 두 개의 미들웨어 콜백이 실행된다.
이 미들웨어 패턴은 여러 객체 간 다대 다의 통신을 하나의 관리 포인트를 통하도록 만들어 관계를 단순하게 만들어준다.