ホームページ  >  記事  >  Java  >  Javaデザインパターンにおけるプロキシパターンの説明例

Javaデザインパターンにおけるプロキシパターンの説明例

黄舟
黄舟オリジナル
2017-09-28 09:24:181607ブラウズ

次のエディターは、Java デザイン パターン - プロキシ パターン (例付きの説明) に関する記事を提供します。編集者はこれがとても良いと思ったので、参考として共有します。エディターをフォローして見てみましょう

プロキシ パターンは、Java で最も一般的なデザイン パターンの 1 つです。 Spring の AOP はプロキシ モードを使用します。

一般に、プロキシ モードは、静的プロキシと動的プロキシの 2 つのタイプに分類されます。

構造クラスの設計パターンとして、その機能はクラスの内部コードを変更せずにクラスを拡張することであり、継承メカニズムを補足します。

例: ユーザーログインの例を使用してプロキシモードを実装してみましょう。

基本的な要件は、ユーザーのログイン機能とニックネーム変更機能を実現することです。

コードに移りましょう。まず IUser インターフェイスとユーザー実装クラスです


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("我还是大风"); 

}

この方法では、クライアントクラスを変更して静的プロキシを追加するだけで、完全に実装されます。しかし、需要は無限にあります。「管理者ロールと第 2 レベルの管理者を追加しました。たくさんのロールがあります。これは恥ずかしいことです。各ロールには静的プロキシ クラスを構築する必要があります。」クラスが爆発するだろう。心配しないでください。動的プロキシ モードがあります。

動的プロキシ モードでは、新しいプロキシ クラスを自分で作成する必要がなく、特定の実装クラス (サブジェクト) を渡すと、デフォルトでプロキシ クラスが生成されます。

基本的に、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);
 }

}

概要: 静的プロキシモードは比較的単純です。キーポイントこれは、実装クラス(サブジェクト本体)ごとに新しいプロキシ クラスを作成することであり、プロキシ クラスはエンティティ クラス(サブジェクト本体)への参照を持ち、aop 制御を含む元の実装クラス(サブジェクト本体)の制御を実現できます。 、など。 2. 静的プロキシには制限があります。エンティティ クラスごとに新しい静的プロキシ クラスを作成する必要がある場合があります。これにより、静的プロキシ クラスが多すぎる可能性があるため、動的プロキシが登場しました。 3. 動的プロキシは、内部的には、オブジェクトを使用してエンティティクラスの参照にアクセスし、リフレクションを使用してエンティティクラスのさまざまなメソッドを取得することで実装を実現します。クラス (サブジェクト 本体) アスペクト指向の AOP プログラミング制御。

4. 上記の記述方法は JDK の動的プロキシですが、この種類の動的プロキシではエンティティ クラスが少なくとも 1 つのインターフェイスを実装する必要があるため、完全ではありません。問題は、すべてのクラスにインターフェイスがあるわけではないため、ここでは完璧ではないということです。

以上がJavaデザインパターンにおけるプロキシパターンの説明例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。