Java学習ノート——設計モード:ダイナミックエージェント


導入
エージェント設計モードの原理:エージェントを使用してオブジェクトをパッケージ化し、元のオブジェクトの代わりにそのエージェントを使用します.元のオブジェクトへの呼び出しはすべてエージェントを介します.プロキシオブジェクトは、メソッド呼び出しを元のオブジェクトに転送するかどうかを決定します.
前の設計モードで述べたエージェントモードは静的エージェントに属し,エージェントクラスとターゲットオブジェクトのクラスがコンパイル中に決定され,プログラムの拡張に不利であることを特徴とする.同時に、各エージェントクラスは1つのインタフェースにしかサービスできないため、プログラム開発では必然的に多くのエージェントが発生します.1つのエージェントクラスですべてのエージェント機能を完了することが望ましい.
概要
動的エージェントとは、クライアントがエージェントクラスを介して他のオブジェクトを呼び出す方法であり、プログラムの実行時に必要に応じて動的にターゲットクラスを作成するエージェントオブジェクトです.
動的エージェントの使用状況:
  • デバッグ
  • リモートメソッド呼び出し
  • ステップ
  • は、エージェントの特定の操作を完了するためにinvokeメソッドを実装する必要がある実装インタフェースInvocationHandlerのクラスを作成する.
    class MyInvocationHandler implements InvocationHandler{
    
        Object obj; //                 
    
        // (1)           ;(2)          
        public Object blind(Object obj) {
            this.obj = obj;
            return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
        }
    
        //                       ,         invoke     
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // method      
            Object returnVal = method.invoke(obj, args);
            return returnVal;
        }
    
    }
    
  • プロキシ対象クラスおよびインタフェース
    interface Subject{
        void action();
    }
    
    //     
    class RealSubject implements Subject{
    
        @Override
        public void action() {
            System.out.println("      ,       !");
        }
    
    }
    
  • を作成する.
  • Proxyの静的方法newProxyInstance(ClassLoader loader,Class[]interfaces,InvocationHandler h)によってSubjectインタフェースエージェントを作成する(ステップ1のコードに現れる)
  • SubjectエージェントによってRealSubject実装クラスを呼び出す方法
    // 1.         
    RealSubject real = new RealSubject();
    // 2.       InvacationHandler       
    MyInvocationHandler handler = new MyInvocationHandler();
    // 3.  blind()  ,            real        Subject       。
    Subject subject = (Subject) handler.blind(real); //   subject        
    subject.action(); //    InvacationHandler       invoke     
    
  • AOP
    Aspect Oriented Programming(AOP)は、フェースプログラミング向けです.
    Proxyを使用して動的エージェントを生成する場合、動的エージェントを空で生成することはありません.これはあまり意味がありません.通常、指定したターゲットオブジェクトに対して動的エージェントを生成します.
    このような動的エージェントはAOPにおいてAOPエージェントと呼ばれ,AOPエージェントはターゲットオブジェクトに代わることができ,AOPエージェントはターゲットオブジェクトのすべての方法を含む.しかし、AOPエージェントのメソッドは、ターゲットオブジェクトのメソッドとは異なります.AOPエージェントのメソッドは、ターゲットメソッドを実行する前に、その後にいくつかの汎用処理を挿入することができます.
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    //   
    interface StudentInfoService{
    	void findInfo(String studentName);
    	void showRole();
    }
    
    //     
    class StudentInfoServiceImpl implements StudentInfoService{
    
    	@Override
    	public void findInfo(String studentName) {
    		System.out.println("The name is " + studentName);
    	}
    
    	@Override
    	public void showRole() {
    		System.out.println("   ");
    	}
    	
    }
    
    class MyHandler implements InvocationHandler {
    
    	private Object obj;
    	
    	public void bind(Object obj) {
    		this.obj = obj;
    	}
    	
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		System.out.println("======      " + method.getName() + "======");
    		Object returnVal = method.invoke(obj, args);
    		System.out.println("======    " + method.getName() + "    ======");
    		return returnVal;
    	}
    	
    }
    
    class AOPFactory{
    	//               
    	public static Object getProxyInstance(Object obj) {
    		MyHandler handler = new MyHandler();
    		handler.bind(obj);
    		return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
    	}
    }
    
    public class TestAOP {
    	public static void main(String[] args) {
    		//            
    		StudentInfoServiceImpl serviceImpl = new StudentInfoServiceImpl();
    		//             
    		StudentInfoService studentInfoService = (StudentInfoService) AOPFactory.getProxyInstance(serviceImpl);
    		//                  
    		studentInfoService.findInfo("runner");
    		studentInfoService.showRole();
    	}
    }
    
    ======      findInfo======
    The name is runner
    ======    findInfo    ======
    ======      showRole======
       
    ======    showRole    ======
    

    まとめ
    コアは、InvocationHandlerインタフェースとProxyクラスの静的メソッドnewProxyInstanceを実現することであり、前者は被エージェントクラスとの関連付け(書き換えのinvokeメソッドがキー)を担当し、後者はエージェントクラスの動的生成を担当する.この2つはnewProxyInstanceの3番目のパラメータに関連付けられ、動的エージェントを実現する.
    AOPは動的エージェントの応用であり、その核心はInvocationHandlerのinvoke法を実現することである.invoke(obj,args)は動的であり、その前後に他のハードコーディングがある可能性がある.
    関連読書:Java学習ノート——Java反射メカニズム