エージェントモード(二)----すべてのインタフェースに対するすべての方法のエージェントの実装を完了する
6069 ワード
前の記事では,静的エージェントの実装方法について述べ,静的エージェントの集約と継承の実装効果の違いを比較した.今日は,動的エージェントを逐次実装し,JDK動的エージェントの実装を模倣する.動的エージェントとは?まず、以前は新しいクラスを作成することによって、被エージェントと同じインタフェースを実現して最終的に目的を達成しました.このように、各被エージェントに対して、新しいエージェントクラスを書く必要があります.このような方法は間違いありません.もしこのようなクラスがあれば、被エージェントオブジェクトに転送すれば、自動的にエージェントオブジェクトを生成するのに役立ちます.それでいいんじゃないですか.Clientクライアントの要件は、 です.動的エージェントに必要な手順: 被エージェントオブジェクトの生成を自動的に支援する必要がある以上、被エージェントクラスを生成し、被エージェントクラスをコンパイルし、そのクラスをメモリにloadし、エージェントオブジェクトを生成することを解決しなければならない.そこで、上記のタイムエージェントを例に挙げて、この問題を解決します. 次に、動的エージェントの異なるインタフェースの実装を行う.ここで考慮すべき問題は,被エージェントのオブジェクトに対して,まずそのすべてのメソッドを取得し,そのすべてのメソッドに対してエージェントを実現するため,一部のエージェントクラスのコードを修正することである. は、まずメソッド体の定義であり、被エージェントオブジェクトを受信するインタフェースクラス、すなわち、 に変更すべきである.インタフェース内のすべての方法を取得する:(ここではjavaの反射機構に関する) エージェントクラスコードをつなぐ方法文字列: 生成コードstrを修正し、メソッド文字列を追加し、実装インタフェースを修正する: コンストラクタのパラメータと返されるオブジェクトの変更:
ここでは,すべてのインタフェースをエージェントできるすべての方法を完了した.しかし、もう一つの問題は、エージェントの論理が死んでいることです.次に、エージェントの論理をカスタマイズできる動的エージェントを実現することです.
Tank tank = new Tank() ;
Moveable tankTimeProxy = (Moveable)Proxy.newInstance(tank) ;
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)
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は我々の生成コードであり外層コードである.詳細な違いは、コードの中で具体的に試してみて、生成されたエージェントクラスの違いを見てみるとわかるはずです.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());
ここでは,すべてのインタフェースをエージェントできるすべての方法を完了した.しかし、もう一つの問題は、エージェントの論理が死んでいることです.次に、エージェントの論理をカスタマイズできる動的エージェントを実現することです.