>Java >java지도 시간 >Java 디자인 패턴의 프록시 패턴 설명 예

Java 디자인 패턴의 프록시 패턴 설명 예

黄舟
黄舟원래의
2017-09-28 09:24:181654검색

다음 편집기에서는 Java 디자인 패턴 - 프록시 패턴(예제 설명)에 대한 기사를 제공합니다. 편집자님이 꽤 좋다고 생각하셔서 지금 공유하고 모두에게 참고용으로 드리도록 하겠습니다. 편집기를 따라 살펴보겠습니다

프록시 패턴은 Java에서 가장 일반적인 디자인 패턴 중 하나입니다. Spring의 AOP는 프록시 모드를 사용합니다.

일반적으로 프록시 모드는 정적 프록시와 동적 프록시의 두 가지 유형으로 나뉩니다.

구조적 클래스의 디자인 패턴으로, 그 기능은 클래스의 내부 코드를 수정하지 않고 클래스를 확장하는 것입니다. 이는 상속 메커니즘을 보완합니다.

예: 사용자 로그인의 예를 사용하여 프록시 모드를 구현해 보겠습니다.

기본 요구 사항은 사용자의 로그인 및 닉네임 수정 기능을 구현하는 것입니다.

코드를 살펴보겠습니다. 먼저 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("我还是大风"); 

}

이렇게 하면 클라이언트 클래스를 수정하고 정적 프록시만 추가하면 완벽하게 구현됩니다. 하지만 요구는 끝이 없습니다. 제품 관리자는 "관리자 역할과 두 번째 수준 관리자를 추가했습니다."라고 말합니다. 많은 역할이 있습니다.

이것은 당황스럽습니다. 각 역할에는 정적 프록시 클래스를 구축하고 수업이 폭발할 것이다. 걱정하지 마세요. 동적 프록시 모드가 있습니다.

동적 프록시 모드는 새 프록시 클래스를 직접 만들 필요가 없다는 것입니다. 특정 구현 클래스(주제)를 전달하면 기본적으로 프록시 클래스가 생성됩니다.

기본적으로 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("使用动态代理后的大风");
  
 }

}

요구로 인해 추가된 관리 클래스


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. 핵심 포인트 각 구현 클래스(주체 본문)에 대해 새 프록시 클래스를 생성하는 것입니다. 프록시 클래스에는 엔터티 클래스(주체 본문)에 대한 참조가 있으므로 aop를 포함하여 원래 구현 클래스(주체 본문)를 제어할 수 있습니다. 통제 등등..

2. 정적 프록시에는 제한이 있습니다. 각 엔터티 클래스에 대해 새 정적 프록시 클래스를 만들어야 할 수 있습니다. 이로 인해 정적 프록시 클래스가 너무 많아질 수 있으므로 동적 프록시가 등장하게 됩니다.

3. 동적 프록시는 특정 구현 클래스(주체 본문)에 국한되지 않고 내부적으로 개체를 사용하여 엔터티 클래스의 참조에 액세스한 다음 리플렉션을 사용하여 엔터티 클래스의 다양한 메서드를 가져옴으로써 구현을 구현합니다. 클래스(주제). 측면 지향 AOP 프로그래밍 제어.

4. 위의 작성 방법은 JDK의 동적 프록시인데, 이러한 종류의 동적 프록시에는 엔터티 클래스가 하나 이상의 인터페이스를 구현해야 하기 때문에 완벽하지 않습니다. 문제는 모든 클래스에 인터페이스가 있는 것은 아니므로 여기서는 완벽하지 않다는 것입니다.

위 내용은 Java 디자인 패턴의 프록시 패턴 설명 예의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.