Java設計モードのエージェントの初探査


JAva設計モードの静的エージェントであり、動的エージェントモードはオブジェクトの構造モードである.プロキシモードは、オブジェクトにプロキシオブジェクトを提供し、プロキシオブジェクトによって元のオブジェクトへの参照を制御します.1つの個体または機構が別の個体または機構を代表していくつかの行為を実行することを意味する.場合によっては、クライアントがオブジェクトを直接参照したくないか、または参照できない場合があります.エージェントオブジェクトは、クライアントとターゲットオブジェクトの間で仲介の役割を果たすことができます.
スタティツクエージェント
  • シーン:例えば、飛行機のチケットを買うとしたら、あなたの行為は航空券を買うことです.航空券を買うには、第三者の代理プラットフォームを通じて、例えばアリ、どこへ行くか、携程などのプラットフォームを通じて買ってあげることができます.このプラットフォームは代理役になります.そうすれば、航空会社で直接切符を買う必要はありません.エージェントロールに行動要件を伝えるだけです.
  • コード1.動作インタフェース
  • の作成
    public interface BuyTicketInterface {
        //     
        void butTicket();
    
    }

    2.クライアントを作成します.クライアントはインタフェースで定義された動作を実現するために、切符を買います.そして自分の行為を実行します.
    public class TravelPeople implements BuyTicketInterface {
        //         ,    。
        public void butTicket() {
            System.out.println("   5 1                  ,  14:00 24:00  ");
        }
    }

    3.エージェント側の機能を作成し、エージェント側もチケットを買う行為を実現しなければならない.そうしないと、クライアントの要求をどのように完成するか、エージェントがチケットを買う過程はクライアントの実行の代わりになる.コードは以下の通りです.
    public class BuyTicketProxy implements BuyTicketInterface{
    
        private TravelPeople travelPeople;
        //
        public BuyTicketProxy(){
        this.travelPeople = new TravelPeople(); 
        }
        /** *               ,          。 */
        public void buyTicket() {
            if(travelPeople != null){
                travelPeople.buyTicket();
            }
        }
    }

    4.エージェントを使用してチケットを購入する.端末行為と代理側の処理、購入シートの機能を実現する.コードは次のとおりです.
    public class TicketService {
    
    
        public static void main(String[] args) {
            TicketService.startBuyTicket();
        }
        //    ,               ,            。
        public static void startBuyTicket(){
            BuyTicketInterface buyTick = new BuyTicketProxy();
            buyTick.buyTicket();
        }
    }

    実行結果
       5 1                  ,  14:00 24:00  

    静的エージェントモデルのメリットとデメリット:ビジネスクラスはビジネスロジック自体に注目するだけで、ビジネスクラスの再利用性を保証します.これは、ビジネスロジックの結合性を低下させながら、エージェントの共通の利点です.欠点:1)エージェントオブジェクトの1つのインタフェースは1つのタイプのオブジェクトにのみサービスし,エージェントする方法が多い場合は,各メソッドにエージェントを行う必要があり,静的エージェントはプログラム規模がやや大きい場合には適任ではない.2)インタフェースにメソッドが追加された場合,すべての実装クラスがこのメソッドを実装する必要があるほか,すべてのエージェントクラスもこのメソッドを実装する必要がある.コードメンテナンスの複雑さが増しました.
    では問題が来て、上記のように(静的エージェント)エージェント・モードを使用する場合、実際のロールはすでに存在し、エージェント・オブジェクトの内部属性として使用する必要があります.しかし、実際に使用する場合、実際のロールはエージェント・ロールに対応する必要がありますが、大量に使用するとクラスが急激に膨張します.また、実際のロールが事前に知られていない場合は、エージェントをどのように使用しますか?Javaの動的エージェントクラスで解決できます.
    ダイナミックエージェント
    動的エージェントクラスのソースコードは,プログラム実行中にJVMによって反射などのメカニズムに従って動的に生成されるため,エージェントクラスのバイトコードファイルは存在しない.エージェントクラスと委任クラスの関係は、プログラムの実行時に決定されます.Javaの反射メカニズムによって実現される.
    1.まず、動的エージェントと密接に関連するJava APIを見てみましょう.
    1)java.lang.reflect.Proxy
    これはJava動的エージェントメカニズムによって生成されるすべての動的エージェントクラスの親であり、インタフェースのセットに対してエージェントクラスとそのオブジェクトを動的に生成する静的メソッドのセットを提供します.Proxyのコードリストは以下の通りです
    //    1:                       
    static InvocationHandler getInvocationHandler(Object proxy) 
    
    //    2:                               
    static Class getProxyClass(ClassLoader loader, Class[] interfaces) 
    
    //    3:                      
    static boolean isProxyClass(Class cl) 
    
    //    4:            、                   
    static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 
    

    2)java.lang.reflect.InvocationHandler
    これは、動的エージェントクラスオブジェクト上のメソッド呼び出しを集中的に処理するためのinvokeメソッドをカスタマイズした呼び出しプロセッサインタフェースで、通常、このメソッドでは委任クラスへのエージェントアクセスが実現されます.動的プロキシクラスオブジェクトを生成するたびに、対応する呼び出しプロセッサオブジェクトを指定します.
    InvocationHandlerdコードのリストは次のとおりです.
    //                       。            ,               
    //           。                                
    Object invoke(Object proxy, Method method, Object[] args) 

    3)java.lang.ClassLoader
    これはクラス・マウンタ・クラスです.クラスのバイトコードをJava仮想マシンにマウントする(JVM)でクラスオブジェクトを定義し、そのクラスが使用されるようにします.Proxyスタティックメソッドによる動的エージェントクラスの生成は、通常のクラスとは異なり、任意の.classファイルに予め保存されているのではなく、JVMによって実行時に動的に生成されるバイトコードです.動的エージェントクラスオブジェクトが生成されるたびにクラス・マウンタ・オブジェクトを指定します.
    2 .動的エージェント実装ステップの具体的なステップは、a.InvocationHandlerインタフェースを実装する独自の呼び出しプロセッサb.ProxyクラスにClassLoaderとエージェントインタフェースタイプ配列を提供する動的エージェントクラスc.呼び出しプロセッサタイプをパラメータとし、反射機構により動的エージェントクラスの構造関数dを得る.呼び出しプロセッサオブジェクトをパラメータとする動的エージェントクラスのコンストラクション関数を使用して動的エージェントクラスオブジェクトを作成する
    // InvocationHandlerImpl     InvocationHandler   ,                     
    //                  ,                 
    InvocationHandler handler = new InvocationHandlerImpl(..); 
    
    //    Proxy     Interface                     
    Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... }); 
    
    //                    
    Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class }); 
    
    //                  
    Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler }); 
    

    3.動的エージェント実装例
    インタフェースを作成します.
    public interface BuyTicketInterface {
    
        void buyTicket();
    }
    

    動的エージェントクラスに対応する呼び出しハンドラクラスの作成
    
     public class BuyTicketHandler implements InvocationHandler {
         /** *                 */
        private Object orginObject;
        //               
        public BuyTicketHandler(Object orginObject){
            this.orginObject = orginObject;
        }
    
    
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result ; 
            //      ;
            doBefore();
              //                 。Method invoke  Object          。
              //           ,            
            result = method.invoke(this.orginObject, args);
            doAfter();
            return result ; 
        }
    
        private void doBefore(){
            System.out.println("    ");
        }
    
    
        private void doAfter(){
            System.out.println("    ");
        }
    
    
    
    }

    動的エージェント・クラス・オブジェクトを生成する手順を示すファクトリ・メソッドを使用して、動的エージェント・オブジェクトのファクトリを生成します.
    /** *            . */
    public class DynProxyFactory {
     //                。
     //      ,                     。
     public static Subject getInstance(){ 
      Subject delegate = new RealSubject();
      InvocationHandler handler = new SubjectInvocationHandler(delegate);
      Subject proxy = null;
      proxy = (Subject)Proxy.newProxyInstance(
        delegate.getClass().getClassLoader(), 
        delegate.getClass().getInterfaces(), 
        handler);
      return proxy;
     }
    }
    

    動的プロキシクライアントクラス
    public class BuyTicketProxy {
        //                。 
         //      ,                     。 
        public static BuyTicketInterface  startBuy(){
            //        
            BuyTicketInterface buyTicket = new TravelPeople();
            //      
            InvocationHandler handler = new BuyTicketHandler(buyTicket);
            //         。
            BuyTicketInterface buy = (BuyTicketInterface)Proxy.newProxyInstance(buyTicket.getClass().getClassLoader(), buyTicket.getClass().getInterfaces(), handler);
            return buy;
        }
    
    }
    

    テストの作成;
    BuyTicketInterface buy = BuyTicketProxy.startBuy();
            buy.buyTicket();

    実行結果:
        
       5 1                  ,  14:00 24:00  
        
    

    まとめ:まず動的に生成されるエージェントクラス自体の特徴です.1)パッケージ:エージェントのインタフェースがpublicの場合、エージェントのインタフェースにpublic以外のインタフェースがある場合(protectまたはprivateとして定義できないため、public以外はデフォルトのpackageアクセスレベル)は、そのインタフェースが存在するパケットとして定義されます(すなわち、パケットパスが空の場合).(com.ibm.developerworksパッケージの非publicインタフェースAがエージェントされていると仮定すると、新しく生成されたエージェントクラスが存在するパッケージはcom.ibm.developerworksである)、動的エージェントクラスがパッケージ管理の問題で機能定義およびアクセスできないことを最大限に保証するために設計された.2)クラス修飾子:このエージェントクラスはfinalおよびpublic修飾子を有し、すべてのクラスにアクセスできるが、再継承できないことを意味します.3)クラス名:形式は「$ProxyN」で、Nは1つずつ増加するアラビア数字であり、ProxyクラスがN回目に生成した動的エージェントクラスを表している.注意すべき点は、Proxyの静的メソッドを呼び出して動的エージェントクラスを作成するたびにN値が増加するわけではない.なぜなら、インタフェースの配列を含む同じインタフェースのセットに対して動的エージェントクラスを繰り返し作成しようとすると、以前に作成したエージェントクラスのクラスオブジェクトを賢く返し、新しいエージェントクラスを作成しようとすることなく、不要なコードの繰り返し生成を節約し、エージェントクラスの作成効率を向上させることができるからです.
    利点:動的エージェントと静的エージェントを比較すると、最大の利点は、インタフェースで宣言されたすべてのメソッドが呼び出しプロセッサの1つのセットのメソッドに移行されて処理されることです.(InvocationHandler.invoke).これにより、インタフェースメソッドの数が多い場合には、静的エージェントのように各メソッドを中継する必要がなく、柔軟な処理を行うことができます.この例では、invokeメソッドには、特定の周辺トラフィック(タスク処理前後時間を記録し、時間差を計算する)が埋め込まれているため、見えません.
    欠点:Proxyはすでに完璧に設計されていますが、まだ限界があります.インターネットエージェントの束縛から抜け出すことができません.その設計はこの残念さを運命付けているからです.動的に生成されたエージェントクラスの継承関係図を思い出すと、Proxyという共通の親がいることになります.Javaの継承メカニズムは、これらの動的エージェントクラスがclassに対する動的エージェントを実現できないことを運命付けている.なぜなら、Javaでは本質的に多くの継承が通用しないからだ.
    多くの理由で、classエージェントの必要性を否定することができますが、classダイナミックエージェントをサポートすることがより良いと信じている理由もあります.インタフェースとクラスの区分は、もともと明らかではありませんが、Javaではこのように細分化されています.メソッドの宣言と定義のみから考慮すると,抽象クラスという名前の2つの混合体がある.抽象クラスに対する動的エージェントを実現するには,その内在的な価値もあると信じている.また、インタフェースが実装されていないため、動的エージェントとは永遠に縁がない歴史的なクラスもあります.このようなことは、小さな残念と言わざるを得ない.最後に,エージェント設計モデルはプロジェクト自体の状況に応じて設計モデルの設計機能を最大化する.プロジェクトを拡張しやすくし、結合性が低い.進む方向です.