엄 살 부리 지 마 세 요. - 1 회: 대리 모드, 동적 대리 와 방향

Public class ViewAction implements Action
{
        public void doAction()
        {
               // View   
               System.out.println(“You could view the information……”);
               ……
}
}
대리 의 뜻 은 이해 하기 쉽다. 이것 은 우리 가 평소에 사용 하 는 대리 의 뜻 을 참고 했다. 즉, 원래 자신 이 직접 해 야 할 어떤 일 은 어떤 이유 로 직접 할 수 없고 사람 을 청해 서 당신 을 대신 할 수 밖 에 없다 는 것 이다. 이것 은 당신 이 일 을 하도록 초 대 받 은 사람 이 바로 대리 이다.예 를 들 어 설 이 지나 면 집에 돌아 가 야 한다. 네가 출근 해 야 하기 때문에 표를 살 시간 이 없 으 면 티켓 중개인 이 너 를 대신 해서 구 매 해 야 한다. 이것 이 바로 대리 모델 이다.이 상황 은 다음 과 같이 형상 적 으로 묘사 할 수 있다.
class:   
{
          :
       {……}
}
 
기차 역 은 표를 파 는 곳 이다. 우 리 는 기차 역 에서 만 표를 살 수 있다 고 가정 한다.표를 파 는 동작 은 실질 적 으로 기차 역 류 가 완성 한 것 이다.
Class:    
{
          :
        {
                   ;
                 .  ;
}
}
 
 고객 이 티켓 중개인 을 찾 아 표를 살 때, 티켓 중개인 을 호출 하여 표를 판다.티켓 중개인 은 사실 두 가지 일 을 했다. 하 나 는 기차 역 에 가서 표를 사 는 것 이 고, 다른 하 나 는 공짜 로 표를 팔 아 서 는 안 되 며, 반드시 중개 비 를 받 아야 한다.당신 이 얻 은 장점 은 기차 역 에 직접 가서 표를 사지 않 아 도 되 고 표를 사 는 시간 을 절약 하여 출근 하 는 것 이다.
    이상 에서 저 희 는 대리 모델 의 상황 과 왜 대리 모델 을 사용 하 는 지 간단하게 모 의 했 습 니 다. 다음은 JAVA 의 대리 모델 을 구체 적 으로 분석 하 겠 습 니 다.
    만약 에 정보 관리 시스템 이 있다 고 가정 하면 일부 사용자 가 정 보 를 조회 할 수 있 는 권한 이 있 고 일부 사용자 가 정 보 를 조회, 추가, 수정 할 수 있 는 권한 이 있 으 며 상기 권한 을 제외 하고 정 보 를 삭제 할 수 있 는 권한 도 있다 면 우리 가 가장 쉽게 생각 할 수 있 는 방법 은 다음 과 같다.
public class ViewAction
{
        // userId    
        ……
        String permission = ……;
       if(permission.equals(Constants.VIEW))
        {
               System.out.println(“You could view the information……”);
               ……
}
}
  다른 동작 들 은 모두 정 보 를 조회 하 는 동작 과 차이 가 많 지 않다.우 리 는 이러한 유형 을 보면 그의 단점 을 쉽게 알 수 있다. 첫째, 권한 계산 과 동작 집행 을 모두 한 가지 유형 에 두 고 이들 의 기능 이 서로 혼합 되 어 사고의 혼란 을 초래 하기 쉬 우 며 유지 와 테스트 를 수정 하 는 것 도 좋 지 않다.한 마디 로 단일 직책 원칙 에 만족 하지 않 는 다.두 번 째 는 고객 이 호출 할 때 구체 적 인 유형 에 의존 하여 확장 과 운행 기간 내의 호출 에 어려움 을 초래 하고 거꾸로 원칙 에 의존 하지 않 는 다 (거꾸로 원칙 (DIP) 은 추상 에 의존 하고 인 터 페 이 스 를 정의 하여 이 를 실현 하 며 구체 적 인 것 에 의존 하지 않 는 다).    이렇게 많은 문제 가 있 는 이상 우 리 는 이런 종류의 재 설 계 를 진행 할 필요 가 있다.사실 이런 종 류 는 프 록 시 모드 를 사용 해 야 한다 고 생각 한 지 오래다.그래, 우리 가 기차 표를 사 는 동작 과 마찬가지 로 동작 류 는 그 동작 을 직접 수행 할 수 없 으 며, 먼저 권한 을 검사 한 후에 야 실행 할 수 있다.먼저 권한 을 검사 한 후에 실 행 된 모든 것 은 하나의 대리 류 입 니 다. 수 정 된 코드 는 다음 과 같 습 니 다.
public interface Action
{
        public void doAction();
}
 우선 의존 전도 원칙 을 충족 시 키 기 위해 인 터 페 이 스 를 설계 하 는 것 이다.
Public class ViewAction implements Action
{
        public void doAction()
        {
               // View   
               System.out.println(“You could view the information……”);
               ……
}
}
     이 종 류 는 기차 역 과 마찬가지 로 동작의 실제 집행자 이다.
Public class ProxyViewAction implements Action
{
        private Action action = new ViewAction();
        public void doAction()
        {
               //              
               if(Permission.getPermission(userId).equals(Constants.VIEW))
               {
                      action.doAction();
}
}
}
  이것 은 대리 류 여서 이해 하기 쉽다.우리 의 Proxy View Action 류 에서 고객 이 진정 으로 하고 싶 은 동작 을 했 습 니 다: doAction () 을 제외 하고 사용자 의 권한 을 추가 로 검사 하 는 동작 도 했 습 니 다.한편, 핵심 동작 을 하 는 doAction () 은 깨끗 한 유형 이다. ViewAction 에서 진행 되 는데 이런 유형 은 핵심 동작 만 하고 다른 것 에 관심 이 없 으 며 단일 한 직책 원칙 을 만족 시 켰 다.     클 라 이언 트 는 에이전트 클래스 를 호출 하여 동작 을 수행 하고 에이전트 클래스 는 권한 판단 과 동작의 집행 을 분리 하여 단일 한 직책 원칙 을 만족시킨다.둘째, 같은 인 터 페 이 스 를 실현 하여 의존 전도 원칙 을 만족 시 켰 다.첫 번 째 생각 보다 훨씬 좋아 졌 다.    프 록 시 뷰 클래스 에서 프 록 시 뷰 클래스 는 도 액 션 () 방법 을 제대로 실행 하지 않 고 뷰 액 션 클래스 에 맡 기 는 것 을 말한다.    프 록 시 류 ProxyViewAction 을 다시 살 펴 보면 인터페이스 Action 뿐만 아니 라 구체 적 인 ViewAction 실현 에 도 의존 하 는 것 을 볼 수 있 습 니 다.이렇게 하면 우리 의 시스템 확장 에 불리 합 니 다. 예 를 들 어 우 리 는 Add 동작, Delete 동작, Modify 동작 등 이 있 습 니 다. 우 리 는 모든 동작 에 하나의 대리 류 를 써 야 합 니 다. 이런 대리 류 는 똑 같은 일 을 하고 권한 판단 을 한 다음 에 위임 해 야 합 니 다.그래서 우 리 는 이러한 대리 에 대해 다시 한 번 추상 적 으로 해서 인터페이스 Action 에 만 의존 하고 구체 적 인 실현 에 의존 하지 않도록 해 야 한다.    이러한 생각 을 실현 하려 면 우 리 는 대리 류 중의 구체 적 인 실현 을 추출 하여 대리 사용자 가 운영 기간 에 구체 적 인 실현 류 를 제공 하도록 해 야 한다. 즉, 이른바 의존 주입 은 다음 과 같다.
Public class ProxyAction implements Action
{
        private Action action;
        public ProxyAction(Action action)
        {
               this.action = action;
}
        public void doAction()
        {
               //              
               if(Permission.getPermission(userId).equals(action.getClass().getName()))
               {
                      action.doAction();
}
}
}
 이렇게 해서 우 리 는 Action 인터페이스의 실현 을 모두 하나의 대리 류 로 대리 할 것 이다.ViewAction 클래스 를 제외 하고 나중에 확 장 된 AddAction,       Modify Action, deleteAction 류 등 은 프 록 시 액 션 을 사용 할 수 있 습 니 다.    저희 클 라 이언 트 는 다음 과 같 습 니 다. Action action = ProxyAction(new ViewAction); Action.doAction();     대리 류 에 대한 의존 주입 을 통 해 우 리 는 대리 류 를 초보 적 으로 어느 정도 확장 시 켰 다.그러나 우 리 는 이 대리 류 가 특정한 인터페이스 에 의존 하 는 것 도 보아 야 한다.이것 은 우리 의 실제 요 구 를 만족 시 키 지 못 한다. 예 를 들 어 우리 시스템 의 권한 통 제 는 보통 전체 시스템 급 이다. 이렇게 시스템 급 의 권한 통 제 는 우 리 는 전체 시스템 에서 통 일 된 인 터 페 이 스 를 추상 화하 기 어렵다. 여러 개의 인터페이스 가 있 을 수 있다. 위의 대리 모델 에 따라 우 리 는 모든 인터페이스 에 하나의 대리 류 를 써 야 한다. 마찬가지 로이런 종류의 기능 은 모두 같다.이것 은 분명히 좋 은 해결 방법 이 아니다.    위의 원인 을 바탕 으로 우 리 는 시스템 이 통 일 된 인터페이스 가 없 는 상황 에서 일부 흩 어 진 대상 의 특정한 동작 에 대해 대리 모델 을 사용 하 는 문 제 를 해결 해 야 한다.JAVA API 는 동적 에이전트 나 동적 위임 기술 을 도입 했다.    동적 에이전트 의 핵심 은 Invocation Handler 인터페이스 입 니 다. 동적 대 리 를 사용 하려 면 이 인 터 페 이 스 를 실현 해 야 합 니 다.이 인터페이스의 위임 임 무 는 invoke (Object) 입 니 다. proxy, Method m, Object[] args) 방법 에서 실 현 된 것: / / invoke 는 호출 의 뜻 / / 핵심 기능 을 호출 하기 전에 동작 을 합 니 다... / 핵심 기능 m. invoke (obj, args); //핵심 기능 을 호출 한 후에 동작 을...    우 리 는 동적 에이전트 의 실 용적 인 반사 메커니즘 이 핵심 기능 을 호출 하 는 것 을 볼 수 있다. m. invoke (obj, args);바로 이러한 반사 메커니즘 의 사용 으로 인해 우 리 는 핵심 기능 을 더욱 유연 하 게 호출 할 수 있 고 특정한 인터페이스 에 의존 하지 않 고 Object 대상 에 의존 할 수 있다.    다음은 동적 대리 나 동적 위임 이 어떻게 사용 되 는 지 구체 적 으로 살 펴 보 겠 습 니 다.
public class ProxyAction implements InvocationHandler {
private Object action;
//    
public ProxyAction(Object action)
{
       this.action = action;
}
public static Object getInstance(Object action)
{
        return Proxy.newProxyInstance(action.getClass().getClassLoader(),
action.getClass().getInterfaces(),new ProxyAction(action));
}
 
public Object invoke(Object proxy, Method m, Object[] args)
               throws Throwable {
        
        Object result;
 
       try {
                      //        ,      
           System.out.println("before method " + m.getName());
                      //    
           result = m.invoke(action, args);
 
       } catch (InvocationTargetException e) {
 
           throw e.getTargetException();
 
       } catch (Exception e) {
 
           throw new RuntimeException("unexpected invocation exception: "
 
                  + e.getMessage());
 
       } finally {
                      //        
           System.out.println("after method " + m.getName());
 
       }
 
       return result;
 
 
}
 
}
 이 프 록 시 클래스 는 먼저 Invocation Handler 인 터 페 이 스 를 실현 했다.그리고 getInstance () 방법 에서 프 록 시 클래스 의 인 스 턴 스 를 얻 었 습 니 다.invoke () 방법 에서 대리 기능 을 실현 하 는 것 도 간단 하 다.    다음은 클 라 이언 트: Action action = (Action)ProxyAction.getInstance(new ViewAction()); Action.doAction();     우 리 는 프 록 시 클래스 가 인터페이스 에 대한 의존 도 클 라 이언 트 로 옮 겨 가 는 것 을 볼 수 있다. 그러면 프 록 시 클래스 는 특정한 인터페이스 에 의존 하지 않 는 다.같은 프 록 시 클래스 ProxyAction 에 대해 서도 다음 과 같은 클 라 이언 트 호출 이 가능 합 니 다: Engine engine = (Engine)ProxyAction.getInstance(new EngineImpl()); Engine.execute();     engine Impl 류 가 Engine 인 터 페 이 스 를 실현 하면 위 에서 처럼 사용 할 수 있 습 니 다.    이제 우 리 는 동적 대리 가 확실히 상당 한 유연성 을 가지 고 있다 는 것 을 알 수 있다.그러나 우 리 는 이 대리 류 는 쓰기 가 비교적 번 거 롭 고 매번 이런 천편일률 적 인 것 을 쓰 는 것 도 많 지 않다 는 것 을 보 았 다. 위임 전의 동작 과 위임 후의 동작 만 서로 다른 대리 에서 다 르 고 다른 것 은 모두 그대로 써 야 한다.만약 이런 대리 류 를 많이 썼 다 면, 약간의 불필요 한 대리 도 있 을 것 이다.우리 가 더욱 최적화 해 야 한다. 여기 서 우 리 는 템 플 릿 방법 모델 을 사용 하여 이 대리 류 를 최적화 시 켜 야 한다. 다음 과 같다.
public abstract class BaseProxy implements InvocationHandler {
private Object obj;
protected BaseProxy(Object obj)
{
       this.obj = obj;
}
public static Object getInstance(Object obj,InvocationHandler instance)
{
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),instance);
}
 
public Object invoke(Object proxy, Method m, Object[] args)
               throws Throwable {
        // TODO Auto-generated method stub
        Object result;
 
       try {
 
           System.out.println("before method " + m.getName());
           this.doBegin();
 
           result = m.invoke(obj, args);
 
       } catch (InvocationTargetException e) {
 
           throw e.getTargetException();
 
       } catch (Exception e) {
 
           throw new RuntimeException("unexpected invocation exception: "
 
                  + e.getMessage());
 
       } finally {
 
           System.out.println("after method " + m.getName());
           this.doAfter();
 
       }
 
       return result;
 
 
}
public abstract void doBegin();
public abstract void doAfter();
 
}
  이렇게 하면 대리 의 실현 류 는 위임 전의 동작 과 위임 후의 동작 에 만 관심 을 가지 면 된다. 다음 과 같다
public class ProxyImpl extends BaseProxy {
protected ProxyImpl(Object o)
{
       super(o);
}
public static Object getInstance(Object foo)
{
        return getInstance(foo,new ProxyImpl(foo));
}
 
//      
public void doBegin() {
        // TODO Auto-generated method stub
       System.out.println("begin doing....haha");
 
}
 
//      
public void doAfter() {
        // TODO Auto-generated method stub
       System.out.println("after doing.....yeah");
 
}
 
}
 위의 코드 를 통 해 우 리 는 대리 실현 류 가 확실히 훨씬 간단 하 다 는 것 을 알 수 있다. 위임 전과 위임 후의 동작 에 만 관심 을 가 졌 다. 이것 은 우리 가 대리 로 서 진정 으로 관심 을 가 져 야 할 것 이다.    이로써 대리 모드 와 동적 대 리 는 일 단락 되 었 다.우 리 는 이 문장의 사족 으로 동태 대 리 를 인용 하여 설명 할 것 이다.    이 화 제 는 바로 방면 을 향 한 프로 그래 밍 이나 AOP 이다.우 리 는 위의 ProxyImpl 류 를 보 았 습 니 다. 그것 의 두 가지 방법 은 doBegin () 과 doAfter () 입 니 다. 이것 은 핵심 동작 을 하기 전과 그 후의 두 가지 캡 처 부분 입 니 다.바로 이 두 개의 절단 부분 이지 만 우리 AOP 의 기초 이다.OOP 에서 doBegin (), 핵심 동작, doAfter () 세 동작 은 여러 가지 유형 에서 항상 함께 있 지만 그들 이 완성 하고 자 하 는 논 리 는 다르다. 예 를 들 어 doBegin () 이 할 수 있 는 것 은 권한 이 고 모든 유형 에서 권한 을 한다.각 유형 에서 핵심 동작 은 각각 다르다.doAfter () 는 로 그 를 만 들 수 있 습 니 다. 모든 클래스 에서 로 그 를 만 듭 니 다.바로 모든 클래스 에서 doBegin () 이나 doAfter () 가 똑 같은 논 리 를 하기 때문에 우 리 는 이 를 추출 하고 단독 분석, 디자인 과 인 코딩 을 해 야 한다. 이것 이 바로 우리 의 AOP 사상 이다.    이렇게 말 하면 우리 의 동적 대 리 는 AOP 를 실현 하 는 기초 가 될 수 있다.이렇게 많아

좋은 웹페이지 즐겨찾기