⭐️for(MyHandlerAdapter : List<MyHandlerAdapter>)⭐️⭐️⭐️⭐️⭐️
부모 인터페이스는 자식 객체를 품을 수 있다!
그러므로 인터페이스인 MyHandlerAdapter 타입의 리스트를 만들면 V3든 V4든 핸들러 어댑터 종류 상관없이 리스트에 저장이 가능하다!
private MyHandlerAdapter getHandlerAdapter(Object handler) {
//handler = MemberFormControllerV4
for (MyHandlerAdapter adapter : handlerAdapters) {//리스트 다 뒤진다.
if(adapter.supports(handler)){//Controller3Adapter 먼저 검사하고, 조건 불충족하면 다음 Controller4Adapter 조건 검사
return adapter;//MyHandlerAdapter adapter를 리턴한다!
}
}
throw new IllegalArgumentException("Handler Adapter를 찾을 수 없습니다.handler"+handler);
}
이제 컨트롤러4가 들어왔을 때도 어댑터로 처리할 수 있는 코드를 작성해본다.
다음 3가지만 추가해서 수정해주면 메인 코드에서는 수정할 것이 없다!
initHandlerMappingMap()과 initHandlerAdapters()은 설정을 하는 부분이기 때문에 이 부분도 메인에서 분리하고, 컨트롤러 핸들링하는 어댑터만 추가해서 구현해주면 메인에는 수정할 것이 하나도 없어지게 된다!
이렇게 인터페이스에 의존하도록 설계하면 OCP를 만족하면서, 확장성 좋게 추가 및 수정이 가능하고, 메인 코드는 전혀 수정할 필요가 없게 된다!
initHandlerMappingMap() : 컨트롤러4 uri가 들어와도 맵핑할 수 있도록 맵에 추가한다.
initHandlerAdapters() : handlerAdapters 리스트에 컨트롤러4에 대한 처리할 수 있도록 ControllerV4HandlerAdapter를 추가한다!
MyHandlerAdapter를 상속받는 ControllerV4HandlerAdapter 구현
핵심⭐️❤️
원래 ControllerV4는 String 타입의 View name 만을 반환하지만, 전체 어댑터 구조를 ModelView를 반환하도록 설계하였기에 이 View name을 가지고 어댑터가 ModelView를 생성해서 리턴하도록 한다!
ControllerV4에서와 똑.같.이 빈 Map 객체 model 먼저 생성하고, 컨트롤러에 넣어주면서 컨트롤러 내부에서 비즈니스 로직 실행하며 model에 데이터 넣어준다.
package hello.servlet.web.frontcontroller.v5.adapter;
import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.v4.ControllerV4;
import hello.servlet.web.frontcontroller.v5.MyHandlerAdapter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class ControllerV4HandlerAdapter implements MyHandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof ControllerV4);
}
@Override
public ModelView handle(HttpServletRequest req, HttpServletResponse res, Object handler) throws ServletException, IOException {
//handler를 V4로 캐스팅한다!(전체 부모 객체 Object로 들어온 애를 그 하위 버전 인터페이스로 캐스팅하는 것이다~!)
ControllerV4 controller = (ControllerV4) handler;
HashMap<String, Object> model = new HashMap<>();
Map<String, String> paramMap = createParamMap(req);
String viewName = controller.process(paramMap, model);//Model과 paramMap 두개 파라미터를 받는다!
//어댑터는 viewName가지고 ModelView를 생성해준다!!!
//Model과 View를 셋팅해준다!
ModelView mv = new ModelView(viewName);//뷰 이름 셋팅
mv.setModel(model);//모델 셋팅
return mv;
}
private Map<String, String> createParamMap(HttpServletRequest req) {
//컨트롤러의 process에 Map<String,String> paramMap을 넘겨줘야한다!!!!!!
Map<String,String> paramMap = new HashMap<>();
req.getParameterNames().asIterator()
.forEachRemaining(paramName->paramMap.put(paramName, req.getParameter(paramName)));
return paramMap;
}
}