javaデザインモード-プロキシモード(実例解説)


プロキシモードはjavaの最も一般的な設計モードの一つである。springのaopは代理モードを使っています。
一般的に、プロキシモードは、静的エージェントと動的エージェントの2つに分類される。
構造類の設計モードとしては、クラスの内部コードを修正しない場合に、クラスを開拓することが作用しており、継承メカニズムの一種である。
eg:以下、ユーザ登録という例について、プロキシモードを実現します。
基本的な需要は、ユーザーのログインとニックネーム機能の変更を実現することです。
上のコードは、まずIUserインターフェースとuser実装クラスです。

public interface IUser {
 //  
 void login(String userId,String password);
 //    
 void editNickname(String nickname);

}

public class User implements IUser {
 
 private String nickname;
 private String userId;
 private String password;
 
 public User(String userId,String password){
  this.userId = userId;
  this.password = password;
 }

 @Override
 public void login(String userId, String password){
  if(this.userId == userId && this.password == password){
   System.out.println("      ");
  }
  else
   System.out.println("      ");
 }

 @Override
 public void editNickname(String nickname) {
  this.nickname = nickname;
  System.out.println("      ,        :"+this.nickname);
 }

}
クライアントクラス

public class Client {
 public static void main(String[] args) {
  //        
  IUser user = new User("firs","123");
  user.login("firs", "123");
  user.editNickname("  ");
}
やはりとても簡単です。しかし、後の製品マネージャーから、ユーザーの行動を記録する機能を追加する必要があります。どうすればいいですか?ユーザークラスを直接修正しますか?いいえ、代理モードを使います。
エージェントクラスを追加して、エージェントクラスに「ユーザーの行動を記録する」という機能を書けばいいです。クラスを変更しないで、カテゴリだけを広げて、エラーの発生を減らすことができます。

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 *            ,               
 * @author Administrator
 *
 */
public class StaticProxy implements IUser {
 private IUser user;
 public StaticProxy(String userId,String password){
  this.user = new User(userId,password);
 }
 
 //      ,         
 void noteLoginInfo(String[] params, String opreate){
  Map<String,Object> loginInfo = new HashMap<>();
  loginInfo.put("params", params);
  loginInfo.put("opreate", opreate);
  loginInfo.put("opreateTime", new Date());
  System.out.println("        ");
 }
 
 @Override
 public void login(String userId, String password){
  
  noteLoginInfo(new String[]{userId, password},"login");
  
  user.login(userId, password);
 }

 @Override
 public void editNickname(String nickname) {
  noteLoginInfo(new String[]{nickname},"editNickname");
  user.editNickname(nickname);
 }

}
クライアントクラス:

public class Client {
 public static void main(String[] args) {
  //        
  IUser user = new User("firs","123");
  user.login("firs", "123");
  user.editNickname("  ");
  
  System.out.println("");
  System.out.println("=============         ===========");
  
  //                      
  //  “    ,    ”     ,            
  IUser proxy = new StaticProxy("firs","123");
  proxy.login("firs", "123");
  proxy.editNickname("     "); 

}
このようにクライアントクラスを修正して、静的なエージェントを追加すればいいです。完璧に実現します。しかし、需要は無限です。製品の管理人があなたに言いました。「私たちは管理人の役を増やしました。二級管理人もいます。」
これは困惑して、すべての役はすべて1つの静的な代理種類を建てて、種類は爆発しました。急がないです。私たちはダイナミックエージェントモードがあります。
ダイナミックプロキシモードは自分でプロキシ類を新築しなくてもいいです。具体的な実現類(主体)を彼に伝えてください。彼はデフォルトであなたにプロキシ類を生成しました。
本質的には、Javaの反射機構を利用して、動作時に、対応するプロキシクラスを動的に生成する。
反射がないと、ダイナミックエージェントがありません。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 *                   
 * @author Administrator
 *
 */
public class DynamicProxy implements InvocationHandler {
 private Object object;
 public DynamicProxy(String userId,String password,Class<?> c){
  Object obj = null;
  try {
   obj = Class.forName(c.getName())
     .getConstructor(String.class,String.class)
     .newInstance(userId,password);
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  this.object = obj;
 }
 
 //      ,         
 void noteLoginInfo(String[] params, String opreate){
  Map<String,Object> loginInfo = new HashMap<>();
  loginInfo.put("params", params);
  loginInfo.put("opreate", opreate);
  loginInfo.put("opreateTime", new Date());
  System.out.println("        ");
 }

 @Override
 public Object invoke(Object proxy, Method method, Object[] args)
   throws Throwable {
  String[] params = new String[args.length];
  for(int i = 0 ;i < args.length ; i++){
   params[i] = args[i].toString();
  }
  noteLoginInfo(params, method.getName());
  return method.invoke(object, args);
 }

}
最後のクライアントクラス:

package com.test.my;

import java.lang.reflect.Proxy;


public class Client {
 public static void main(String[] args) {
  //        
  IUser user = new User("firs","123");
  user.login("firs", "123");
  user.editNickname("  ");
  
  System.out.println("");
  System.out.println("=============         ===========");
  
  //                      
  //  “    ,    ”     ,            
  IUser proxy = new StaticProxy("firs","123");
  proxy.login("firs", "123");
  proxy.editNickname("     ");
  
  System.out.println("");
  System.out.println("=============         ===========");
  
  DynamicProxy dynamicProxy = new DynamicProxy("firs","123",Admin.class);
  
  ClassLoader cl = Admin.class.getClassLoader();
  IUser iuser = (IUser)Proxy.newProxyInstance(cl,
        new Class[]{IUser.class}, dynamicProxy);
  iuser.login("firs","123");
  iuser.editNickname("          ");
  
 }

}
需要により増加したAdmin類

public class Admin implements IUser {
 
 private String nickname;
 private String userId;
 private String password;
 
 public Admin(String userId,String password){
  this.userId = userId;
  this.password = password;
 }

 @Override
 public void login(String userId, String password){
  if(this.userId == userId && this.password == password){
   System.out.println("      ");
  }
  else
   System.out.println("      ");
 }

 @Override
 public void editNickname(String nickname) {
  this.nickname = nickname;
  System.out.println("      ,        :"+this.nickname);
 }

}
まとめ:
1.静的エージェントモードは比較的簡単であり、各実装クラス(subject本体)に対して、aopの制御など、エンティティクラス(subject本体)の参照があるエージェントクラスを新規に作成することができる。
2.静的エージェントには限界があり、各エンティティ類に対して静的エージェントを新規に作成する必要があり、このようにして静的エージェントが多すぎる場合があり、動的エージェントが生まれてきた。
3.動的エージェントは、具体的な実装クラス(subject本体)に限定されず、その内部では、Objectを用いてエンティティ類の参照にアクセスし、反射を利用してそのエンティティ類の様々な方法を獲得し、クラス(subject本体)を実現するための切断面AOPプログラミング制御を実現する。
4.上記の書き方はJDKのダイナミックエージェントであり、特に完璧ではない。このような動的エージェントはエンティティクラスが少なくとも一つのインターフェースを実現する必要があるからだ。問題はすべての種類にインターフェースがあるわけではないので、ここで完璧ではないです。
以上は私自身の代理モデルに対する理解です。もし間違いがあれば、ご指摘をお願いします。ありがとうございます。
以上のjavaデザインモード-プロキシモード(実例解説)は、小編集が皆さんに提供した内容の全部を共有しています。参考にしていただければと思います。どうぞよろしくお願いします。