반응형
문서를 정리하다가 예전에 헤드퍼스트 디자인 패턴 책을 읽고 정리해 놓은 파일이 있어 옮겨봅니다.

==============================================================

디자인 원칙
    - 애플리케이션에서 달라지는 부분을 찾아내고, 달라지지 않는 부분으로부터 분리한다.
    - 구현이 아닌 인터페이스에 맞춰서 프로그래밍한다.
    - 상속보다는 구성을 활용한다.
    - 서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결한하는 디자인을 사용해야 한다.
    - 클래스는 확장에 대해서는 열려 있어야 하지만 코드 변경에 대해서는 닫혀 있어야 한다.
       (OCP : Open-Closed Principle)
    - 추상화된 것에 의존하도록 만들어라. 구상클래스에 의존하도록 만들지 않도록 한다.
    - 최소 지식 원칙 - 정말 친한 친구하고만 얘기하라.
       (다음 네 종류의 객체의 메서드만 호출한다.
         1. 객체 자체 / 2. 메서드에 매개변수로 전달된 객체 / 3. 그 메서드에서 생성하거나 인스턴스를 만든 객체 / 4. 그 객체에 속하는 구성 요소)
    - 헐리우드 원칙 - 먼저 연락하지 마세요. 저희가 연락 드리겠습니다.
    - 클래스를 바꾸는 이유는 한 가지 뿐이어야 한다.
    + ... 나중에 어떻게 바뀔 것인가?


스트래티지 패턴(Strategy Pattern)
    - 알고리즘군을 정의하고 각각을 캐슐화하여 교환해서 사용할 수 있도록 만든다.
    - 알고리즘을 사용하는 클라이언트와는 독립적으로 알고리즘을 변경할 수 있다.
    - 구성을 사용한다.
    - 일반적으로 서브클래스를 만드는 방법을 대신하여 유연성을 극대화하기 위한 용도로 쓰인다.
    - 예: QuarkBehavior & FlyBehavior
    

옵저버 패턴(Observer Pattern)
    - 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고
       자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의존성을 정의한다.
    - 주제(Subject) & 옵저버(Observer)
    - Observable & Observer:
         Observable 에 register, remove, notify 가 있고, 
         Observer 에 update 가 있다. (notify 에서 update 를 호출)
    - 예: 신문 구독 서비스, 기상관측 시스템
    

데코레이터 패턴(Decorator Pattern)
    - 객체에 추가적인 요건을 동적으로 첨가한다.
    - 데코레이터는 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다.    
    - 예: 스타버즈 커피
    
    
팩토리 패턴(Factory Pattern)    
    - 팩토리 메서드 패턴 :
       객체를 생성하기 위한 인터페이스를 정의하는데, 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정하게 만든다.
       클래스의 인스턴스를 만드는 일을 서브클래스에 맡긴다.
    - 제품을 생산하는 부분과 사용하는 부분을 분리시킬 수 있다.
    - 추상 팩토리 패턴 :
       인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 구상 클래스를 지정하지 않고 생성한다.
       구상 클래스는 서브 클래스에 의해 만들어진다.


싱글턴 패턴(Singleton Pattern)
    - 해당 클래스의 인스턴스가 하나만 만들어지고,
       어디서든지 그 인스턴스에 접근할 수 있도록(전역 접근) 하기 위한 패턴
       
       
커맨드 패턴(Command Pattern)
    - 요구 사항을 객체로 캡슐화 할 수 잇으며, 매개변수를 써서 여러 가지 다른 요구 사항을 집어넣을 수 있다.
       또한 요청 내역을 큐에 저장하거나 로그로 기록할 수도 잇으며, 작업취소 기능도 지원 가능하다.
    - 예: 리모콘
    - 서블릿의 doGet(), doPost() 또는 스트럿츠의 Action() 메서드도 커맨드 패턴이지 않을까?
    

어댑터 패턴(Adapter Pattern)
    - 한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환한다.
       어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다.  
       

퍼사드 패턴(Facade Pattern)
    - 어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공한다.
       퍼사드에서 고수준 인터페이스를 정의하기 때문에 서브시스템을 더 쉽게 사용할 수 있다.
    - 서브시스템의 호출을 퍼사드에서 처리해준다. (기본 명령 호출 정도랄까...)
    - 일련의 클래스들에 대한 인터페이스를 단순화 시킨다.
    
    - 각 패턴별 차이점:
       데코레이터 패턴 : 인터페이스는 바꾸지 않고 책임(기능)만 추가
       어댑터 패턴 : 한 인터페이스를 다른 인터페이스로 변환
       퍼사드 패턴 : 인터페이스를 간단하게 바꿈


템플릿 메서드 패턴(Template Method Pattern)
    - 메서드에서 알고리즘의 골격을 정의한다.
       알고리즘의 여러 단계 중 일부는 서브클래스에서 구현할 수 있다.
       템플릿 메서드를 이용하면 알고리즘의 구조는 그대로 유지하면서 서브클래스에서 특정 단계를 재정의할 수 있다.
    - 스트래티지 패턴과 다른 점:
       템플릿 메서드 패턴은 알고리즘의 개요를 정의한다. 실제 작업 중 일부는 서브클래스에서 처리.
       스트래티지 패턴은 객체 구성을 통해서 알고리즘을 캡슐화 및 구현
    - 예) Arrays.sort(배열); --- compareTo() 를 구현하도록 되어 있다.
            Applet , init(), start(), stop(), destory()
            그렇다면 서블릿에도 템플릿 메서드가 쓰이는 거구나. init() - service() - destory()

            
이터레이터 패턴(Iterator Pattern)
    - 컬렉션 구현 방법을 노출시키지 않으면서도
       그 잡합체 안에 들어있는 모든 항목에 접근할 수 있게 해주는 방법을 제공한다.
    - 컬렉션의 구현을 드러내지 않으면서 컬렉셔네 있는 모든 객체들에 대해 반복작업할 수 있다.
    

컴포지트 패턴(Composite Pattern)
    - 객체들을 트리 구조로 구성하여 부분과 전체를 나타내는 계층구조로 만들 수 있다.
       이 패턴을 이용하면 클라이언트에서 개별 객체와 다른 객체들로 구성된
       복합 객체(composite)를 똑같은 방법으로 다룰 수 있다.
    - 클라이언트에서 객체 컬렉션과 개별 객체를 똑같은 식으로 처리할 수 있다.
    - 예) 트리 구조의 패턴, 디렉토리 구조
    - 예) XMLObject 객체가 컴포지트 패턴을 구현한 게 아닐까
    

스테이트 패턴(State Pattern)
    - 객체의 내부 상태가 바뀜에 따라서 객체의 행동을 바꿀 수 있다.
       마치 객체의 클래스가 바뀌는 것과 같은 결과를 얻을 수 있다.
    - 상태 전환의 흐름을 결정하는 코드를 어느 쪽에 집어넣는지 잘 고려해야 한다.
       (상태 객체인지, Context 객체인지)
    - 각 상태를 클래스로 캡슐화함으로써 나중에 변경시켜야 하는 내용을 국지화시킬 수 있다.
    - 스트래티지 패턴:
          어떤 클래스의 인스턴스를 만들고 그 인스턴스에게 어떤 행동을 구현하는 전략 객체를 건내준다.
       스테이트 패턴:
          컨텍스트 객체를 생성할 때 초기 상태를 지정해주는 경우 이후로는 컨텍스트 객체가 알아서 상태를 변경.
          
          
프록시 패턴(Proxy Pattern)
    - 어떤 객체에 대한 접근을 제어하기 위한 용도로 대리인이나 대변인에 해당하는 객체를 제공하는 패턴
    - 다른 객체를 대변한느 객체를 만들어서 주 객체에 대한 접근을 제어할 수 있다.
    - 원격프록시(remote proxy): 원격 객체에 대한 접근 제어
                                                클라이언트와 원격 객체 사이에서 데이터 전달을 관리
       가상프록시(virtual proxy): 생성하기 힘든(인스턴스를 만드는 데 많은 비용이 드는) 자원에 대한 접근 제어
       보호프록시(protection proxy): 접근 권한이 필요한 자원에 대한 접근 제어
                                                     호출하는 쪽의 권한에 따라서 객체에 있는 메소드에 대한 접근 제어
       방화벽 프록시: 일련의 네트워크 자원에 대한 접근 제어
       스마트 레퍼런스 프록시: 주 객체가 참조될 때마나 추가 행동을 제공. 객체에 대한 레퍼런스 개수를 세는 등
       캐싱 프록시: 비용이 많이 드는 작업의 결과를 임시로 저장
                          웹 서버 프록시 또는 컨텐츠 관리 및 퍼블리싱 시스템 등에서 사용
       동기화 프록시: 여러 스레드에서 주 객체에 접근하는 경우 안전하게 작업을 처리할 목적(분산 환경 등에서 사용)
       복잡도 숨김 프록시: 복잡한 클래스들의 집합에 대한 접근을 제어하고 복잡도를 숨겨줌
                                     퍼사드 프록시라고도 함.
                                     프록시에서는 접근을 제어하지만 퍼사드 패턴에서는 대체 인터페이스만 제공
       지연 복사 프록시: 클라이언트에서 필요로 할 때까지 객체가 복사되는 것을 지연시킴으로써 객체의 복사 제어
       
    - 아래 객체들은 모두 클라이언트와 객체 사이에 끼여들어서 요청을 전달한다.
         데코레이터 패턴: 클래스에 새로운 행동을 추가하기 위한 용도
         어댑터 패턴: 다른 객체의 인터페이스를 바꿔주기 위한 용도
         프록시 패턴: 어떤 클래스에 대한 접근을 제어하기 위한 용도
    - java.reflect.Proxy 에 기능이 내장되어 있다.
    
    
디자인 패턴 정의
    - 패턴이란 특정 컨텍스트 내에서 주어진 문제에 대한 해결책이다.
    - 어떤 컨텍스트 내에서 일련의 제약조건에 의해 영향을 받을 수 있는 문제에 봉착했다면,
       그 제약조건 내에서 목적을 달성하기 위한 해결책을 찾아낼 수 있는 디자인을 적용하면 된다.    
      

주의점 및 추가 사항      
    - 디자인 패턴의 과다한 사용은 불필요하게 복잡한 코드를 초래할 수 있다.
       항상 가장 간단한 해결책으로 목적을 달성할 수 있도록 하고, 반드시 필요할 때만 디자인 패턴을 적용하자.      
    - 코딩할 때 어떤 패턴을 사용하고 있는지 주석으로 적어주자.
       클래스와 메서드 이름을 만들 때도 사용 중인 패턴이 분명하게 드러날 수 있도록 해보자.
       다른 개발자들이 그 코드를 볼 때 무엇을 어떻게 구현했는지 훨씬 빠르게 이해할 수 있다.

출처 : http://ohgyun.com/279


반응형
반응형



출처 : http://javacan.tistory.com/entry/

반응형
반응형

인터셉터는 필터와 유사한 동작을 한다. 요청이 controller 에 전달되고 또는 나가는 시점에 요청, 또는 응답을 가로채어 원하는 작업을 수행해줄 수 있다.

 인터셉터에서 사용할 수 있는 세 가지 메소드는 preHandler,  postHandle,  afterCompletion 이다.

preHandle() 메소드는 요청이 controller에서 들어가기 전, poastHandle()은 요청이 controller에 의해 처리되고, 뷰로 보내지기 전,

afterCompletion() 메소드는 뷰까지 보여지고 난 후, 필요한 작업을 수행할 수 있다. 마치 AOP와 조금 유사한 모습을 보이고 있다.


- preHandle : 클라이언트의 요청을 컨트롤러에 전달하기 전에 호출됨. false를 리턴하면 다음 내용은 실행하지 않는다.
- postHandle : 클라이언트의 요청을 처리한 뒤에 호출됨. 컨트롤러에서 예외가 발생되면 실행하지 않는다.
- afterCompletion : 클라이언트 요청 처리뒤 클리이언트에 뷰를 통해 응답을 전송한뒤 실행 됨. 뷰를 생설항때 예외가 발생해도 실행된다
 

아래는 urlHandlerMapping에 인터셉터를 인젝션해주고 있다. 이 맵핑이 정의하는 url로 들어오는 요청은 인터셉터에 의해 가로채진다.

  1. <!-- Member : 로그인한 사람 허용 -->
     <bean id="memberSecureUrlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
         <property name="interceptors">
             <list>
              <ref bean="loginCheckInterceptor"/>
             </list>
         </property>
         <property name="urlMap">
             <map>
              <entry key="/member/edit.do" value-ref="memberSimpleFormController"/>
              <entry key="/member/logout.do" value-ref="memberMultiActionController"/>
          </map>
         </property>
     </bean>

 

 아래는 preHandler()  메소드를 사용하여, session을 검사하여 로그인 체크를 하고 있다. 로그인이 되지 않은 요청이면, 요청을 끝내버리고,

로그인 된 요청이면 컨트롤러에게 요청이 전달될 것이다. 인터셉터에서 반환된 요청에 의해 웹브라우저에서는 하얀 화면이 보여질 것이다.

  1. public class LoginCheckInterceptor extends HandlerInterceptorAdapter {
  2.  private String sessionUserIdKey;
       ....

  3.  // 로그인 했는지 체크

     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
         HttpSession session = request.getSession(false);
         if (session == null) {
          // 처리를 끝냄 - 컨트롤로 요청이 가지 않음
          return false;
      }

  4.   String userId = (String)session.getAttribute(this.sessionUserIdKey);
         if (userId == null) { 
          return false;
         }
      return true;
     }
     
     
     @Override
     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
     
         super.postHandle(request, response, handler, modelAndView);
     }
     
     
     @Override
     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  5. super.afterCompletion(request, response, handler, ex);

  6.   }
  7. }



Spring MVC - Annotation Base HandlerInterceptor

Spring core에서는 AOP를 이용하여 처리내용의 전, 후에 일괄적으로 적용하고 싶은 처리를 추가할수가 있다. 하지만 AOP는 interface를 구현한 곳에만 사용할 수가 있습니다. 그래서 Spring MVC의 Controller에는 상용할수 없죠 자 그럼 만약 로그인 체크를 해야한다면 모든 Controller에 로그인 체크 로직을 넣어줘야할까?. 아니다! 그럼 상위 Controller를 만들고 여기에 로그인 체크로직을 넣고 모든 Controller가 이를 상속 받아 쓰면 어떨까. 그남아 났군.. 이런 것을 위해 Spring MVC 에서는 HandlerMapping이 HandlerInterceptor를 이용하해서 Controller가 요청하는 처리의 전과, 후후에 원하는 기능을 수행할수 있도록 해준다고한다.  ( 뭐 깊숙한 내용까지 알려면 더 공부를하고, 아니면 그냥 Controller에서도 AOP와 같이 쓸수 있도록 제공해준다고 알자 ) HandlerInterceptor는 세가지 메소드를 정의한다

--*   * This implementation always returns <code>true</code>.   --  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)      throws Exception {   return true;  }

 --*   * This implementation is empty.   --  public void postHandle(    HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)    throws Exception {  }

 --*   * This implementation is empty.   --  public void afterCompletion(    HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)    throws Exception {  }

접기

- preHandle : 클라이언트의 요청을 컨트롤러에 전달하기 전에 호출됨. false를 리턴하면 다음 내용은 실행하지 않는다. - postHandle : 클라이언트의 요청을 처리한 뒤에 호출됨. 컨트롤러에서 예외가 발생되면 실행하지 않는다. - afterCompletion : 클라이언트 요청 처리뒤 클리이언트에 뷰를 통해 응답을 전송한뒤 실행 됨. 뷰를 생설항때 예외가 발생해도 실행된다. Interceptor의 구현 org.springframework.web.servlet.HandlerInterceptor 를 직접 구현해서 클래스를 작성해도 되지만 이러면 세개의 메소드를 모두 구현해야한다. 즉 preHandle 만 필요해도 postHandle과 afterCompletion 두 메소드를 모두 구현해야한다. 이를위해 Spring에는 HandlerInterceptorAdaptor 클래스를 제공한다. 이는 이미 HandlerInterceptor interface를 구현한 클래스로 위의 세개의 메소드를 이미 구현하고 있어 필요한것만 구현해서 사용하면 된다. - Interceptor 구현

public class LoginCheckInterceptor extends HandlerInterceptorAdaptor {     @Override     public boolean preHandle(HttpServletRequest request,                                           HttpServletResponse response,                                           Object handler) throws Exception{          if ( !isLogin() ) {              return false;         }         return true;     } }

- dispatcher-servlet.xml의Interceptor 설정

<bean id="annotationMapper"              class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">     <property name="interceptors">         <list>             <ref bean="userLoginInterceptor"/>         </list>     </property>     <property name="alwaysUseFullPath" value="true"/> </bean> <bean id="userLoginInterceptor" class="com.questionbox.interceptor.UserLoginInterceptor" />

위와 같이 할때는 모든 페이지 URL에서 userLoginInterceptor를 실행하게 된다. 그리고  <list>    <ref bean="userLoginInterceptor"/>     <ref bean="userLoginInterceptor2"/>     <ref bean="userLoginInterceptor3"/> </list> 과 같이 여러 인터페이스를 줄수도 있다.


반응형

+ Recent posts