blog

デザイン・パターン - プロキシ・パターン

プロキシとは?例えば、海外買い付け専門の友人がいて、海外に買い付けに行くことができない場合、友人の代理でしか買い付けができないので、その友人が代理人の役割になります。また、訴訟を起こすために弁護士を雇...

Feb 22, 2020 · 6 min. read
シェア

I. 概要

代理人とは何ですか?例えば、友人のサークルは、海外購入の友人に特化している、彼らは購入するために海外に行くことができない、彼らは唯一の購入の方法を介して行うことができますので、彼はエージェントの役割である;訴訟は弁護士を雇う必要があり、弁護士も訴訟を遂行するために弁護士の全権委任の役割の代理人である;宅配便を迎えに行く時間の到着に物事を購入するために他の人に委託し、あなたがピックアップするために友人のエージェントをさせることができます友人もエージェントの役割を果たしています。簡単な例を通して、エージェントモードとは何かを理解します。プロキシパターンは、ターゲットオブジェクトにアクセスするプロキシオブジェクトを介して、つまり、ターゲットオブジェクトにアクセスする別の方法を提供します。そうすることの利点は、追加の機能操作に基づいてターゲットオブジェクトの実装を強化することができる、つまり、ターゲットオブジェクトの機能を拡張することです。

プロキシパターンのキーポイントは、プロキシオブジェクトとターゲットオブジェクトです。プロキシオブジェクトはターゲットオブジェクトの拡張であり、ターゲットオブジェクトを呼び出します。また、プロキシパターンは静的プロキシと動的プロキシに分けられます。

第二に

、静電気除去剤

静的プロキシは、通常、インターフェイスまたは親クラスを定義し、ターゲットオブジェクトは、プロキシオブジェクトと同じインターフェイスを実装するか、同じ親クラスを継承します。ここでは、通常、プロキシオブジェクトは、宅配便を拾うために友人のエージェントのようないくつかの制約を実行するため、唯一の彼のエージェントは、行を拾うようにする必要があり、宅配便を開く必要はありません、または事の使用;もちろん、宅配便が破損している場合、またはいくつかの異常が、また、操作を返すために友人のエージェントを委託する必要があるので、エージェントの操作が多くなる可能性がありますので、一般的なインターフェイスまたは親クラスを記述することは、より直感的です。静的なプロキシを理解しやすくなります。

以下はまだ具体的な指示を行うには、弁護士の訴訟の例です。まずすべてのプロセスの様々な、当事者や弁護士がメソッドを実装する必要が含まれています訴訟インターフェイスを、書き込みます。

/**
 * 議事録インターフェース
 */
public interface LawSuit {
 String TAG = "XXX";
 // 
 void start();
 // 
 void statement();
 //証拠を提供する
 void provideEvidence();
 // 
 void end();
}

もうひとつは、当事者が訴訟インターフェースを実装し、抽象メソッドで当事者独自のロジックを実装することです。

/**
 *  
 */
public class Litigant implements LawSuit {
 @Override
 public void start() {
 Log.e(TAG, "当事者たちはこう言う!閣下!");
 }
 @Override
 public void statement() {
 Log.e(TAG, "当事者曰く:被告は悪意を持ってバンパーステッカーを貼る");
 }
 @Override
 public void provideEvidence() {
 Log.e(TAG, "当事者が言う:私は監視の証拠を持っている");
 }
 @Override
 public void end() {
 Log.e(TAG, "当事者が言う:私は終わった");
 }
}

プロキシはLitigationインターフェイスを実装し、クライアントへの参照を保持します。

/**
 * プロキシ
 */
public class Lawyer implements LawSuit {
 private Litigant litigant;
 public Lawyer(Litigant litigant){
 this.litigant = litigant;
 }
 @Override
 public void start() {
 litigant.start();
 Log.e(TAG, "プロキシはこう言う!こんにちは!");
 }
 @Override
 public void statement() {
 Log.e(TAG, "プロキシはこう言う:プレゼンテーションを始める");
 litigant.statement();
 Log.e(TAG, "プロキシはこう言う");
 }
 @Override
 public void provideEvidence() {
 Log.e(TAG, "プロキシは言う:私たちは証拠を与え始める");
 litigant.provideEvidence();
 Log.e(TAG, "プロキシ弁護士は言った:我々はすべての証拠を提供した");
 }
 @Override
 public void end() {
 litigant.end();
 Log.e(TAG, "プロキシは言う:こちら側は終わった");
 }
}

最後にテストが実行され、プリントアウトは以下のようになります。プロキシのメソッドを見ると、クライアントクラスのメソッドを呼び出す際に、独自のロジックを拡張できることがわかります。

Litigant litigant = new Litigant();
Lawyer lawyer = new Lawyer(litigant);
lawyer.start();
lawyer.statement();
lawyer.provideEvidence();
lawyer.end();

静的プロキシの概要は、上記のコードテストを通じて、静的プロキシの使用は実際には非常に簡単です。プロキシクラスのメソッドを呼び出すときに、ターゲットオブジェクトのメソッドの最後の実際の実行は、プロキシクラスは、ターゲットオブジェクトの関数を変更することはできませんが、ターゲットオブジェクトの関数を拡張することができます。もちろん、いくつかの欠陥は、共通のインターフェイスが変更されると、プロキシオブジェクトとターゲットが影響を受けることです。プロキシクラスが多すぎる場合、それはまた、クラスの数の増加につながる、維持することは容易ではありません。そこで、これらの問題を解決するために、動的プロキシを使用する必要があります。

、ダイナミックエージェント

java.lang.reflect.InvocationHandlerjava.lang.reflect.Proxy動的プロキシでは共有インターフェースの使用は必要ありませんが、プロキシオブジェクトの生成にはJDKのインターフェースとクラスのnewProxyInstance静的メソッドの使用が必要です。

それでは早速コードを書いていきましょう。まず、InvocationHandlerインターフェイスを実装するクラスを作成する必要があります。クラスでは、プロキシオブジェクトを取得するメソッドを定義し、このメソッドは、newProxyInstanceキーを使用して、次のいくつかのパラメータのnewProxyInstanceメソッドを説明します:

  • ClassLoader loader: 現在のターゲット・オブジェクトに使用するクラス・ローダーを指定します;
  • クラス [] interface: 対象オブジェクトが実装するインターフェースの型;
  • InvocationHandler h:イベントハンドリング、ターゲットオブジェクトのメソッドの実行は、イベントハンドラのメソッドをトリガします、パラメータとしてターゲットオブジェクトのメソッドの現在の実行を渡します。

続いて、InvocationHandlerインターフェースのinvokeメソッドのパラメーターの説明です:

  • Object proxy: プロキシオブジェクト。getProxy メソッドで生成されるオブジェクトです;
  • メソッド method: 現在呼び出されているメソッド;
  • Object[] args: 現在のメソッドを呼び出すために渡される引数。
/**
 * 動的プロキシ
 */
public class DynamicProxy implements InvocationHandler {
 private static final String TAG = "XXX";
 private Object target;
 /**
 * プロキシオブジェクトとターゲットオブジェクトの間にプロキシ関係を確立し、プロキシオブジェクトを返す
 * @param target ターゲット・オブジェクト
 * @return プロキシ・オブジェクト
 */
 public Object getProxy(Object target) {
 this.target = target;
 return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
 }
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 if("statement".equals(method.getName())){
 Log.e(TAG, "プロキシはこう言う:プレゼンテーションを始める");
 }else if("provideEvidence".equals(method.getName())){
 Log.e(TAG, "プロキシは言う:私たちは証拠を与え始める");
 }
 //上記は、ターゲット・オブジェクトへの呼び出しのロジックである。
 Object obj = method.invoke(target,args);
 //以下は、ターゲット・オブジェクトを呼び出した後のロジックである。
 if("start".equals(method.getName())){
 Log.e(TAG, "プロキシはこう言う!こんにちは!");
 }else if("statement".equals(method.getName())){
 Log.e(TAG, "プロキシはこう言う");
 }else if("provideEvidence".equals(method.getName())){
 Log.e(TAG, "プロキシ弁護士は言った:我々はすべての証拠を提供した");
 }else if("end".equals(method.getName())){
 Log.e(TAG, "プロキシは言う:こちら側は終わった");
 }
 return obj;
 }
}

Object obj = method.invoke(target,args);invokeメソッドでは、ステートメントへの呼び出しが表示され、リフレクションの使用に関連するリフレクションがあり、リフレクションの使用については、他のブログ記事を参照することができます、ここではあまり多くの説明はありません。このステートメントが実行されると、実際にターゲットオブジェクトのメソッドを呼び出します。

プロキシオブジェクトは、ターゲットオブジェクトのメソッドを呼び出す前後に他のロジックで拡張することができます。ここでは、プロキシオブジェクトが異なる情報を出力するように、異なるメソッドの実行に応じてメソッド名を決定します。最後に、それをテストして、以下のようなプリントアウトを得ます。

DynamicProxy dynamicProxy = new DynamicProxy();
LawSuit lawSuit = (LawSuit) dynamicProxy.getProxy(new Litigant());
lawSuit.start();
lawSuit.statement();
lawSuit.provideEvidence();
lawSuit.end();

ダイナミックプロキシの概要は、プロキシオブジェクトはインターフェイスを実装する必要はありませんが、ターゲットオブジェクトは、インターフェイスを実装する必要があります。ダイナミックプロキシの中核は、InvocationHandlerインタフェースとProxy.newProxyInstance静的メソッドであり、その使用は複雑ではありません。

3つの概要

プロキシモードもよく使われるモードの1つです。もちろん、動的なプロキシに比べて、静的なプロキシは、より頻繁に使用する必要があり、それはまた、使用することは非常に簡単で便利です。Androidのプロキシモードは、このようなクロスプロセス通信として、多く使用され、アクティビティは、これらのサーバーとクライアントの相互作用に関与される起動、もちろん、より多くの興味の例よりも確かに複雑な使用は、また、記事のこのシリーズを見ることができます。

githubアドレス:

Read next

ElasticSearch ドキュメントに対する基本的な CRUD およびバッチ操作。

文書作成\n1.文書の自動生成_id\nリクエストを\nPOST\n{\n "user": "cb"、\n """: "T",\n "発言

Feb 22, 2020 · 3 min read