下面小編就為大家帶來一篇java設計模式-代理模式(實例講解)。小編覺得蠻不錯的,現在就分享給大家,也給大家做個參考。一起跟著小編過來看看吧
代理模式是java最常見的設計模式之一。 spring的aop就是使用了代理模式。
一般而言,代理模式分為靜態代理程式和動態代理兩種。
作為結構類別的設計模式,作用在於不修改類別內部程式碼的情況下,對類別進行拓展,是繼承機制的一種補充。
eg :以下就使用者登入這個範例實作一下代理模式。
基本需求是:實作使用者的登入和修改暱稱功能。
上程式碼,先是IUser介面與user實作類別
1 2 3 4 5 6 7 | public interface IUser {
void login(String userId,String password);
void editNickname(String nickname);
}
|
登入後複製
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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);
}
}
|
登入後複製
客戶端類別
#
1 2 3 4 5 6 7 | public class Client {
public static void main(String[] args) {
IUser user = new User( "firs" , "123" );
user.login( "firs" , "123" );
user.editNickname( "大风" );
}
|
登入後複製
還是很簡單的。可是後面產品經理跟你說,我們需要增加一個記錄使用者行為的功能,這下該怎麼辦呢?直接修改user類別?不不不,用代理模式。
增加一個代理類,在代理類裡面寫「記錄用戶行為」的功能就好,不修改類,只拓展類,減少錯誤發生。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | import java.util. Date ;
import java.util.HashMap;
import java.util.Map;
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);
}
}
|
登入後複製
客戶端類別:
#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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的反射機制在運行時動態地產生了對應的代理類別。
沒有反射,就沒有動態代理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util. Date ;
import java.util.HashMap;
import java.util.Map;
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) {
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);
}
}
|
登入後複製
最後的客戶端類別:
#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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類別
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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中文網其他相關文章!