エージェントモード(二)----すべてのインタフェースに対するすべての方法のエージェントの実装を完了する

6069 ワード

前の記事では,静的エージェントの実装方法について述べ,静的エージェントの集約と継承の実装効果の違いを比較した.今日は,動的エージェントを逐次実装し,JDK動的エージェントの実装を模倣する.
  • 動的エージェントとは?まず、以前は新しいクラスを作成することによって、被エージェントと同じインタフェースを実現して最終的に目的を達成しました.このように、各被エージェントに対して、新しいエージェントクラスを書く必要があります.このような方法は間違いありません.もしこのようなクラスがあれば、被エージェントオブジェクトに転送すれば、自動的にエージェントオブジェクトを生成するのに役立ちます.それでいいんじゃないですか.Clientクライアントの要件は、
    Tank tank = new Tank() ;
    Moveable tankTimeProxy = (Moveable)Proxy.newInstance(tank) ;
    
  • です.
  • 動的エージェントに必要な手順:
  • 被エージェントオブジェクトの生成を自動的に支援する必要がある以上、被エージェントクラスを生成し、被エージェントクラスをコンパイルし、そのクラスをメモリにloadし、エージェントオブジェクトを生成することを解決しなければならない.そこで、上記のタイムエージェントを例に挙げて、この問題を解決します.
  • public class Proxy {
        public static Moveable newInstance(Moveable m) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            //        ,         
            String str =
                    "package dynamicProxy ;" +
                            "public class TankTimeProxy implements Moveable {
    " + " public TankTimeProxy(Moveable m) {
    " + " this.m = m;
    " + " }
    " + "
    " + " private Moveable m ;
    " + "
    " + " @Override
    " + " public void move() throws InterruptedException {
    " + " long startTime = System.currentTimeMillis() ;
    " + " m.move();
    " + " long endTime = System.currentTimeMillis() ;
    " + " System.out.println(\"time : \" + (endTime - startTime));
    " + " }
    " + "}
    " ; // // System.getProperty("user.dir") String fileName = System.getProperty("user.dir") + "/src/dynamicProxy/TankTimeProxy.java" ; File file = new File(fileName) ; FileWriter fw = new FileWriter(file) ; fw.write(str); fw.flush(); fw.close(); // , JDK6 JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler() ; // StandardJavaFileManager StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null,null,null) ; // Iterable units = standardJavaFileManager.getJavaFileObjects(fileName) ; // JavaCompiler.CompilationTask task = javaCompiler.getTask(null,standardJavaFileManager,null,null,null,units) ; // task.call() ; standardJavaFileManager.close(); // load // class URL[] urls = new URL[]{new URL("file:/" + System.getProperty("user.dir") + "/src/")} ; // classLoader URLClassLoader ucl = new URLClassLoader(urls) ; // laod Class c = ucl.loadClass("dynamicProxy.TankTimeProxy") ; // Moveable Constructor constructor = c.getConstructor(Moveable.class) ; // Moveable proxy = (Moveable) constructor.newInstance(new Tank()); return proxy ; } }
    以上のコードにより、システムがエージェントオブジェクトを生成するために必要なステップを解決しました.では問題が来て、今私たちは静的なエージェントしか実現できません.どうやって動的エージェントを実現しますか?
  • 次に、動的エージェントの異なるインタフェースの実装を行う.ここで考慮すべき問題は,被エージェントのオブジェクトに対して,まずそのすべてのメソッドを取得し,そのすべてのメソッドに対してエージェントを実現するため,一部のエージェントクラスのコードを修正することである.
  • は、まずメソッド体の定義であり、被エージェントオブジェクトを受信するインタフェースクラス、すなわち、
  • に変更すべきである.
    public static Moveable newInstance(Moveable m)
    
    :
    public static Object newInstance(Class inface)
    
  • インタフェース内のすべての方法を取得する:(ここではjavaの反射機構に関する)
  • Method[] methods = Method[] methods = inface.getMethods() ; 
    
  • エージェントクラスコードをつなぐ方法文字列:
  • String methodStr ="" ;
    for(Method m : methods){
        methodStr +=
                "    @Override
    " + " public void " + m.getName() + "() {
    " + " try{
    " + " Method md = " + inface.getName() + ".class.getMethod(\""+ m.getName() +"\");
    " + " handler.invoke(this,md) ;
    " + " } catch (Exception e){
    " + " e.printStackTrace() ;
    " + " }
    " + " }" ; }
    ここは多くの人が疑問を持っているかもしれませんが、Method md = " + inface.getName() + ".class.getMethod(\""+ m.getName() +"\");
    "
    ここはなぜMethod md = mで代用できないのでしょうか.実はここでは内外層コードのネスト問題に関連している.methodStrはエージェントクラスの文字列を生成するためであり,その含むmethodは内層コードであり,そのメソッドを取得するには,転送されたインタフェースおよびメソッド名で取得し,mは我々の生成コードであり外層コードである.詳細な違いは、コードの中で具体的に試してみて、生成されたエージェントクラスの違いを見てみるとわかるはずです.
  • 生成コードstrを修正し、メソッド文字列を追加し、実装インタフェースを修正する:
  • String str =
            "package dynamicProxy ;
    " + "import java.lang.reflect.Method;
    " + "public class TankTimeProxy implements " + inface.getName() + " {
    " + " public TankTimeProxy(Moveable m) {
    " + " this.m = m;
    " + " }
    " + "
    " + " private " + inface.getName + " m ;
    " + "
    " + methodStr + "}
    " ;
  • コンストラクタのパラメータと返されるオブジェクトの変更:
  • Constructor constructor = c.getConstructor(inface) ;
    Object proxy =  constructor.newInstance(new Tank());
    


    ここでは,すべてのインタフェースをエージェントできるすべての方法を完了した.しかし、もう一つの問題は、エージェントの論理が死んでいることです.次に、エージェントの論理をカスタマイズできる動的エージェントを実現することです.