首頁 >Java >java教程 >java設計模式之代理模式實例講解

java設計模式之代理模式實例講解

黄舟
黄舟原創
2017-09-28 09:24:181660瀏覽

下面小編就為大家帶來一篇java設計模式-代理模式(實例講解)。小編覺得蠻不錯的,現在就分享給大家,也給大家做個參考。一起跟著小編過來看看吧

代理模式是java最常見的設計模式之一。 spring的aop就是使用了代理模式。

一般而言,代理模式分為靜態代理程式和動態代理兩種。

作為結構類別的設計模式,作用在於不修改類別內部程式碼的情況下,對類別進行拓展,是繼承機制的一種補充。

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("大风");
}

還是很簡單的。可是後面產品經理跟你說,我們需要增加一個記錄使用者行為的功能,這下該怎麼辦呢?直接修改user類別?不不不,用代理模式。

增加一個代理類,在代理類裡面寫「記錄用戶行為」的功能就好,不修改類,只拓展類,減少錯誤發生。


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

}

因為需求而增加的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主體)新建一個代理類,該代理類內有實體類(subject主體)的引用,因此可實現對原有實現類別(subject主體)的控制,包括aop的控制等。

2.靜態代理是有限制的,對於每個實體類可能都需要新建一個靜態代理類,這樣子可能會造成靜態代理類過多的情況,所以動態代理應運而生了。

3.動態代理不限於具體的實現類別(subject主體),在其內部是用object訪問實體類別的引用,再利用反射獲得該實體類別的各種方法,從而實現對實作類別(subject主體)的面向切面AOP編程控制。

4.上述的寫法是JDK裡的動態代理,不是特別完美,因為這種動態代理需要實體類別實現至少一個介面。問題是並不是所有的類別都會有接口,所以說不完美在這裡。

以上是java設計模式之代理模式實例講解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn