下面小編就為大家帶來一篇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中文網其他相關文章!