詳細設計パターンプロキシモード(プロキシ)とコード例

プロキシモードを定義します

  プロキシモードを定義します。何らかの理由で、あなたは、オブジェクトへのアクセスを制御するプロキシを提供することを目的とする必要があります。この場合、オブジェクトが適合しないか、また手数料エージェントモデルモードとして知られているアクセスとターゲットオブジェクトとの間の仲介として、ターゲット・オブジェクトへのプロキシオブジェクトを直接参照にアクセスすることはできません。

第二に、なぜプロキシモードを使用します

  • 仲介アイソレーション:いくつかのケースでは、クライアントクラスは望んでいないか、または直接デリゲートオブジェクトを参照することはできません、プロキシクラスのオブジェクトは、クライアントとデリゲートオブジェクトクラス間の仲介の役割を果たすことができる、あるプロキシクラスと委譲クラスが実装同じインターフェイス
  • 開閉原則として、増加した機能:顧客に加えて、プロキシクラスが仲介クラスとデリゲートクラスである、我々はまた、追加機能を追加するために、プロキシクラスでデリゲートの機能を拡張することができ、我々は唯一のプロキシクラスを変更することなく、これを実行する必要がありますその後、コード設計を開閉の原則に沿って、委譲クラスを変更します。デリゲートメッセージ、フィルタメッセージ、デリゲートへのメッセージを転送し、返された結果のその後の取り扱いの前処理のためにとのように主要な責任を代行。演技のクラス自体は、実際にサービスを実現しませんが、委譲クラスを呼び出すことにより、同じ相関法は、特定のサービスを提供します実際のビジネス機能が委譲クラスによって実装されていますが、ビジネス機能の実行前と後にいくつかの公共サービスを追加することができます。たとえば、私たちは、プロジェクトのキャッシュに参加し、これらの機能を記録したい、我々は完全にプロキシクラス、およびパッケージ化された委譲クラスをオープンする必要はありませんを使用することができます。

第三に、プロキシモードの長所と短所

  プロキシモードの主な利点は以下のとおりです。

  • 仲介役を果たし、クライアントと対象物とターゲットオブジェクトの役割を保護するためにプロキシモード。
  • プロキシオブジェクトは、ターゲットオブジェクトの機能を拡張することができます。
  • 対象物を分離することができるクライアント・プロキシ・モード、結合度をある程度低減されます。

  プロキシモードの主な欠点は以下のとおりです。

  • クライアントと対象物との間で、増加するプロキシオブジェクトである遅い要求処理が発生します。
  • これは、システムの複雑さを増加させます。

第四に、構造および実装代理店モデル

  薬剤は、種々の方法があることを理解共通静的剤であり、動的プロキシ(JDKの動的プロキシ、CGLIBの動的プロキシ)ので、次の3つの実装ずつ説明します。

  1、帯電防止剤

  静的プロキシモード構造は、ほとんどが実際のトピックへのアクセスを可能にする、本当のテーマが含まれるように抽象的なテーマを定義することで、プロキシを継承し、比較的簡単です。次のようにプロキシモードの主な役割は以下のとおりです。

  • 抽象トピック(主題)カテゴリ:実際のビジネスの方法やテーマインタフェースまたは抽象クラス宣言によって達成プロキシオブジェクト。
  • レアルテーマ(実物)カテゴリ:抽象特定のビジネストピックを達成、実際のオブジェクトは、プロキシオブジェクトによって表され、オブジェクトは究極の基準となります。
  • プロキシ(代理)クラス:実際のテーマと同じインタフェースを提供し、内部が実際の被写体への参照が含まれ、それは、アクセス制御、または実際のテーマの機能を拡張することができます。

  図に示す構造。

            

  コードは以下の通りであります:

パブリック クラスProxyTest 
{ 
    公共 静的 ボイドメイン(文字列[]引数)
    { 
        プロキシプロキシ = 新しい新しいプロキシ(); 
        proxy.Request(); 
    } 
} 
// 抽象に関する
インターフェーステーマ
{ 
    無効(要求); 
} 
// 実際のテーマ
クラス RealSubject 実装の件名
{ 
    公共 のリクエスト()
    { 
        System.out.printlnは( "アクセス本当のテーマ別のアプローチ..." ); 
    } 
} 
// プロキシ
クラスプロキシ実装件名
{ 
    プライベートRealSubject RealSubject;
     公共 ボイド要求()
    { 
        IF(RealSubject == NULL 
        { 
            RealSubject = 新しい新しいRealSubject(); 
        } 
        preRequest(); 
        realSubject.Request(); 
        postRequest(); 
    } 
    公共 ボイドpreRequest( )
    { 
        のSystem.out.println( "前処理前のアクセスの実際のテーマ。" ); 
    } 
    公共 ボイドpostRequest() 
    {
        System.out.println(「訪問本当のテーマの後のフォローアッププロセス。」); 
    } 
}

  出力は次のようになります。

前のアクセス本当のテーマに前処理。
アクセス方法...本当のテーマ
訪問の本当のテーマの後に後続の処理。

  静的エージェントの長所と短所

  • 利点:ターゲットオブジェクト、ターゲットの拡張子を変更することなく、関数内で行うことができます。
  • 短所:プロキシオブジェクトは、ターゲットオブジェクトとプロキシオブジェクトを増大させるためのインタフェースメソッドを維持しなければならないと、同時にあまりにも多くのターゲットオブジェクトと同じインタフェース、および非常に多くのプロキシクラス、クラスを実装する必要があるため。

  2、動的プロキシ(JDKの動的プロキシ)

  エージェントは、手動で静的プロキシクラスに問題が、この問題を解決するための動的プロキシ、JDKのダイナミックプロキシが付属していますされているの1の多くを作成します。JDKで再び実行している私たちの本当の時間のための動的プロキシオブジェクトを作成するには、のInvocationHandlerを達成するために、独自のダイナミックを介して作用します。次のようにその構造は次のとおりです。

        

  この例では、次のようにコードが実装され、自動車の開始の一例を示しています。

// ターゲットクラスインターフェース
インターフェースカー{
     ボイドRUN(); 
} 

// ターゲットクラス
クラスベンツ実装車{ 

    @Override 
    公共 ボイドRUN(){ 
        System.out.printlnは( "ベンツはアップ実行" ); 
    } 
} 

クラスCarUtils {
     公共の 静的な 無効methodBefore(){ 
        System.out.printlnは( "点火前に実行する... ..." ); 
    } 
    
    公共の 静的な 無効methodAfter(){ 
        System.out.printlnはは(「シフト後に実行されます。 ... ... " ); 
    }
}

クラス MyInvocationHandle 実装のInvocationHandler {
     プライベートオブジェクトのターゲット。
    公共 ボイドがsetTarget(オブジェクトターゲット){
         この .TARGET = ターゲット。
    } 
    @Override 
    パブリック(オブジェクトプロキシ、メソッドのメソッド、オブジェクト[]引数)を呼び出すオブジェクトがスローのThrowable { 
            CarUtils.methodBefore()。
            method.invoke(ターゲット、引数)。
            CarUtils.methodAfter(); 
            リターン ヌル
    } 
} 

// 生产代理对象的工厂
クラスMyProxyFactory {
     公共の 静的オブジェクトgetProxy(オブジェクトターゲット){ 
        MyInvocationHandleハンドル = 新しいMyInvocationHandle()。
        handle.setTarget(ターゲット)
        オブジェクトプロキシ = たとえば、Proxy.newProxyInstance(target.getClass()のgetClassLoader()、target.getClass()でgetInterfaces()、ハンドル。) 戻り値のプロキシ。
    } 
 } 

パブリック クラスProxyTest {
     公共 静的 ボイドメイン(文字列[]引数){ 
      車車 = 新しいベンツ()。
      車のプロキシ = (車)MyProxyFactory.getProxy(車)。
      proxy.run();
    } 
}

   たとえば、Proxy.newProxyInstance()メソッドは、3つのパラメータを取ることに注意してください:

  • ClassLoader loader:指定したクラスローダを使用して、現在のターゲット・オブジェクトローダは、固定を得ることです
  • Class<?>[] interfaces:ターゲットオーディエンスを達成するためのインタフェースの種類の種類を確認するための汎用的な方法の使用
  • InvocationHandler指定动态处理器,ターゲット・オブジェクトのメソッドを実行する方法は、イベント・ハンドラをトリガします

  JDKの動的プロキシの概要:静的エージェントに比べもののビジネスインタフェースへの依存を軽減しながら、エージェントが大幅結合度を減らし、私たちの開発タスクのダイナミックを低減します。しかし、それは唯一のインタフェースクラスの達成をサポートすることができますJDKのダイナミックプロキシが付属しています。

  3、動的プロキシ(CGLIBの動的プロキシ)

  JDKダイナミックプロキシクラスがインタフェースで定義されたビジネス・メソッドを実装する必要があり、何のクラスのためのインタフェース、およびどのようにCGLIBを必要として動的プロキシを、達成することはありません。バイトコード技術の一番下でCGLIBは、原則的には、クラスのバイトコード技術のサブクラスを作成することで、インターセプトのメソッド呼び出しの傍受技術は、すべてのサブクラスで親クラスのメソッドは、クロス織りロジックを流れ。しかし、継承を使用するので、それは最終的に、プロキシクラスに変更することはできません。

  下に示すように、我々は、動的プロキシCGLIB MethodInterceptorの、関係を示すCGLIB動的プロキシクラスを実装することによって達成さ:

              

   コードは以下の通りであります:

クラスArraySort {
     公共 ボイドクイック(INT [] ARR){ 
        は、Arrays.sort(ARR)。
    } 

    公共 ボイド selectSort(INTは[] ARR){
         ためには、INTは、I <arr.length; iが0 = I ++ ){
             ためINT J = I + 1、J <arr.length; J ++ ){
                 場合(ARR [I ]> ARR [J]){
                     int型温度= 0 
                    TEMP = ARR [I]。
                    ARR [I] = ARR [J]。
                    ARR [J] = TEMP。
                } 
            } 
        } 
    } 

    公共 ボイドバブルソート(INT [] ARR){
         ためINTが I = 0、I <arr.length - 1; I ++ ){
             ためのint型 J = 0; J <arr.length - 1 - I; J ++ ){
                 場合(ARR [J]> ARR [J + 1 ]){
                     int型温度= 0 
                    TEMP = ARR [J]。
                    ARR [J] = ARR [J + 1 ]。
                    ARR [J + 1] = TEMP。
                } 
            } 
        } 
    } 
} 

クラス CglibInteceptor 実装MethodInterceptorの{ 

    プライベートオブジェクトのオブジェクト。

    公共CglibInteceptor(Objectオブジェクト){
         この .object = オブジェクト。
    } 

    @Override 
    パブリックオブジェクトインターセプト(オブジェクトo、メソッドのメソッド、オブジェクト[]、MethodProxy methodProxyオブジェクト)スローのThrowable { 

        するSystem.out.println( "CGLIB动态代理执行前に" )。
        オブジェクトの結果 =method.invoke(オブジェクト、オブジェクト)。
        System.out.println( "CGLIB动态代理执行后" ); 

        戻り値の結果; 
    } 

    パブリックオブジェクトgetProxy(){ 
        エンハンサーエンハンサー = 新しいエンハンサー()。
        enhancer.setCallback(この); 
        enhancer.setSuperclass(object.getClass())。
        リターンenhancer.create(); 
    } 
} 
パブリック クラスCGLibProxyTest { 公共 静的 ボイドメイン(文字列[]引数){ INT [] ARR = 新しい INT [100000 ]。 にとってINTは私= 0; I <arr.length; I ++ ){ ARR [I] =(INT)(Math.random()×1000 )。 } ArraySort arraySort = 新しいArraySort()。 arraySort =(ArraySort)新しいCglibInteceptor(arraySort).getProxy(); arraySort.bubbleSort(ARR)。 arraySort.selectSort(ARR)。 arraySort.quickSort(ARR)。 } }

  CGLIBエージェントの要約: 高性能ダイナミックプロキシJDKが作成したよりも動的プロキシオブジェクトCGLIBを作成するために、オブジェクトが、時間はそれがはるかにJDKよりもプロキシオブジェクトCGLIBを作成するのにかかります。JDKの方法を使用してその逆CGLIBを持つオブジェクト権利、およびバイスがより適切であることをので、一つのケースのために頻繁にターゲットを作成する必要はありません。それが動的に作成されるためとCGLIB方法ので、最終的な方法のためのサブクラスでは、エージェントを変更することはできません。

  これらは、プロキシの実装の3種類があります。JDKダイナミックプロキシエージェントは動的であり、CGLIBは春AOPの基本です。AOPプログラミングの春に:対象物がJDK剤とのインターフェースを実現するためのコンテナに追加されている場合、ターゲットオブジェクトがインタフェースを実装していない場合、CGLIB剤と。

おすすめ

転載: www.cnblogs.com/jing99/p/12596334.html