# Facade Pattern 새로운 멤버 유진 라인 주니어(Eugenio Reinn Jr.)가 처리 중인 서블릿에 134개 라인이 추가된 파일을 커밋했다. 하지만 추가된 코드들이 실제로 하는 일은 요청을 처리하는 것 뿐이었다. 즉 클래스들을 임포트해서 사용한 것이 전부이다. 이것은 한 줄짜리 커밋이어야 했다. 페드로: 얼마나 많은 줄이 커밋되었는지 누가 신경이나 쓰나요? 이브: 신경쓰는 사람이 있을 수 있죠. 페드로: 어디가 문제인지 봅시다. class OldServlet { @Autowired RequestExtractorService requestExtractorService; @Autowired RequestValidatorService requestValidatorService; @Autowired TransformerService transformerService; @Autowired ResponseBuilderService responseBuilderService; public Response service(Request request) { RequestRaw rawRequest = requestExtractorService.extract(request); RequestRaw validated = requestValidatorService.validate(rawRequest); RequestRaw transformed = transformerService.transform(validated); Response response = responseBuilderService.buildResponse(transformed); return response; } } 이브: 오 이런…​ 페드로: 이것은 개발자를 위한 내부 API에요. 요청을 처리할 때마다, 서비스 4개를 써야 하는데, 관련된 모든 임포트를 포함해야 하고, 그래서 이런 코드가 된 거죠. 이브: 리팩토링을 해보죠…​그러니까…​ 페드로: …​파사드 패턴. 모든 의존성(dependencies)을 하나의 접점으로 모아서 API를 단순화하죠. public class FacadeService { @Autowired RequestExtractorService requestExtractorService; @Autowired RequestValidatorService requestValidatorService; @Autowired TransformerService transformerService; @Autowired ResponseBuilderService responseBuilderService; RequestRaw extractRequest(Request req) { return requestExtractorService.extract(req); } RequestRaw validateRequest(RequestRaw raw) { return requestValidatorService.validate(raw); } RequestRaw transformRequest(RequestRaw raw) { return transformerService.transform(raw); } Response buildResponse(RequestRaw raw) { return responseBuilderService.buildResponse(raw); } } 페드로: 그래서 어떤 서비스, 혹은 일단의 서비스가 필요하게 되면 단지 파사드만 쓰면 되죠. class NewServlet { @Autowired FacadeService facadeService; Response service(Request request) { RequestRaw rawRequest = facadeService.extractRequest(request); RequestRaw validated = facadeService.validateRequest(rawRequest); RequestRaw transformed = facadeService.transformRequest(validated); Response response = facadeService.buildResponse(transformed); return response; } } 이브: 잠깐만요, 방금 모든 의존성을 한 곳으로 옮기고, 매번 그것을 사용한다…​라는 거죠? 페드로:네, 어떤 기능이 필요할 때마다, FacadeService를 사용하죠. 필요한 의존성은 이미 거기에 있으니까요. 이브: 하지만 중개자(Mediator) 패턴에서도 같은 일을 했잖아요? 페드로: 중개자는 행위 패턴이죠. 모든 의존성을 중개자에게 몰아넣고, 거기에 새로운 행위를 추가하죠. 이브: 그러면 파사드는? 페드로: 파사드는 구조 패턴이죠, 파사드 패턴에는 새로운 기능을 추가하지 않아요, 그냥 기존 기능들을 노출할 뿐이죠. 이브: 알겠어요. 하지만 그런 작은 차이에 붙이는 이름 치고는 정말 별나게 거창한 이름이군요. 페드로: 아마도. 이브: 다음 클로저 코드는 이름공간들을 가져와서 사용하고 있어요. (ns application.old-servlet (:require [application.request-extractor :as re]) (:require [application.request-validator :as rv]) (:require [application.transformer :as t]) (:require [application.response-builder :as rb])) (defn service [request] (-> request (re/extract) (rv/validate) (t/transform) (rb/build))) 이브: 파사드로 모든 서비스를 노출시키고 (ns application.facade (:require [application.request-extractor :as re]) (:require [application.request-validator :as rv]) (:require [application.transformer :as t]) (:require [application.response-builder :as rb])) (defn request-extract [request] (re/extract request)) (defn request-validate [request] (rv/validate request)) (defn request-transform [request] (t/transform request)) (defn response-build [request] (rb/build request)) 이브: 그리고 사용하면 되죠. (ns application.old-servlet (:use [application.facade])) (defn service [request] (-> request (request-extract) (request-validate) (request-transform) (request-build))) 페드로: :use와 :require의 차이는 뭐죠? 이브: 거의 비슷해요, 하지만 :require는 이름공간을 매번 함수 앞에 붙여줘야 하는 반면, :use는 바로 그럴 필요 없이 바로 사용가능하죠. 페드로: 그러면, :use가 더 좋네요. 이브: 아뇨, :use는 조심해야 해요. 기존 이름공간에서 같은 이름을 사용하면 충돌이 날 수 있죠. 페드로: 오, 무슨 말인지 알겠어요. 어떤 이름공간에서 (:use [application.facade])를 호출할 때마다, 파사드에 있는 함수들 모두가 사용 가능하다? 이브: 네. 페드로: 아주 비슷하네요.