Java代理模式的深入了解
一、靜態(tài)代理模式
1.1、 代理模式的定義:
由于某些原因需要給某對象提供一個代理以控制對該對象的訪問。這時,訪問對象不適合或者不能直接引用目標(biāo)對象,代理對象作為訪問對象和目標(biāo)對象之間的中介。
比如在有些情況下,一個客戶不能或者不想直接訪問另一個對象,這時需要找一個中介幫忙完成某項任務(wù),這個中介就是代理對象。例如,購買火車票不一定要去火車站買,可以通過 12306 網(wǎng)站或者去火車票代售點買。又如找女朋友、找保姆、找工作等都可以通過找中介完成。

靜態(tài)代理:由程序員創(chuàng)建代理類或特定工具自動生成源代碼再對其編譯,在程序運行前代理類的 .class 文件就已經(jīng)存在了。
代碼實例:實現(xiàn)增刪改查操作,通過代理
接口:
package com.proxyPattern.staticProxy2;
/**
* @author wang
* @version 1.0
* @packageName com.proxyPattern.staticProxy2
* @className UserService
* @date 2021/12/27 17:54
* @Description 服務(wù)接口
*/
public interface UserService {
void add();
void delete();
void update();
void query();
}真實類(這里是服務(wù)類)
package com.proxyPattern.staticProxy2;
/**
* @author wang
* @version 1.0
* @packageName com.proxyPattern.staticProxy2
* @className UserServiceImp
* @date 2021/12/27 17:55
* @Description 服務(wù)實現(xiàn)類
*/
public class UserServiceImp implements UserService{
@Override
public void add() {
System.out.println("添加了一條數(shù)據(jù)");
}
@Override
public void delete() {
System.out.println("刪除了一條數(shù)據(jù)");
}
@Override
public void update() {
System.out.println("修改了一條數(shù)據(jù)");
}
@Override
public void query() {
System.out.println("查詢了一條數(shù)據(jù)");
}
}代理類
package com.proxyPattern.staticProxy2;
/**
* @author wang
* @version 1.0
* @packageName com.proxyPattern.staticProxy2
* @className UserServiceProxy
* @date 2021/12/27 17:56
* @Description 服務(wù)代理類
*/
public class UserServiceProxy implements UserService {
private UserServiceImp userServiceImp;
public UserServiceProxy() {
}
public void setUserServiceImp(UserServiceImp userServiceImp) {
this.userServiceImp = userServiceImp;
}
@Override
public void add() {
getLog("add");
userServiceImp.add();
}
@Override
public void delete() {
getLog("delete");
userServiceImp.delete();
}
@Override
public void update() {
getLog("update");
userServiceImp.update();
}
@Override
public void query() {
getLog("add");
userServiceImp.query();
}
public void getLog(String message) {
System.out.println("日志:" + message + "語句執(zhí)行了");
}
}客戶端測試類
package com.proxyPattern.staticProxy2;
/**
* @author wang
* @version 1.0
* @packageName com.proxyPattern.staticProxy2
* @className Customer
* @date 2021/12/27 18:00
* @Description 客戶終端測試類
*/
public class Customer {
public static void main(String[] args) {
UserServiceImp userServiceImp = new UserServiceImp();
UserServiceProxy p = new UserServiceProxy();
p.setUserServiceImp(userServiceImp);
p.add();
p.update();
p.delete();
p.query();
}
}
/**
* 執(zhí)行結(jié)果:
* 日志:add語句執(zhí)行了
* 添加了一條數(shù)據(jù)
* 日志:update語句執(zhí)行了
* 修改了一條數(shù)據(jù)
* 日志:delete語句執(zhí)行了
* 刪除了一條數(shù)據(jù)
* 日志:add語句執(zhí)行了
* 查詢了一條數(shù)據(jù)
*/上述代碼看到我們并沒有使用userServiceImp去執(zhí)行方法,而是使用了一個代理類去執(zhí)行,這就是代理模式,類似于你租房并沒有找房東租房,而是找的一個中間代理人中介來完成租房這個動作。
1.2、代理模式的優(yōu)缺點
那么代理模式有哪些優(yōu)點呢?
1、可以使得我們的真實角色更加純粹 ,不再去關(guān)注一些公共的事情
2、公共的業(yè)務(wù)由代理來完成 . 實現(xiàn)了業(yè)務(wù)的分工
3、公共業(yè)務(wù)發(fā)生擴展時變得更加集中和方便
缺點
1、代理模式會造成系統(tǒng)設(shè)計中類的數(shù)量增加
2、在客戶端和目標(biāo)對象之間增加一個代理對象,會造成請求處理速度變慢;
3、增加了系統(tǒng)的復(fù)雜度;
如何解決這些問題呢?就靠下面的動態(tài)代理模式來解決
二、動態(tài)代理模式
動態(tài),是指在程序運行時,運用反射機制動態(tài)創(chuàng)建而成
沒錯,動態(tài)的代理模式使用的是反射,而且要自己寫一個動態(tài)代理類去動態(tài)的獲取一個代理類
代碼實例:案例同上,只不過采用的是動態(tài)代理模式
服務(wù)實現(xiàn)類(真實類)
package com.proxyPattern.staticProxy2;
/**
* @author wang
* @version 1.0
* @packageName com.proxyPattern.staticProxy2
* @className Customer
* @date 2021/12/27 18:00
* @Description 客戶終端測試類
*/
public class Customer {
public static void main(String[] args) {
UserServiceImp userServiceImp = new UserServiceImp();
UserServiceProxy p = new UserServiceProxy();
p.setUserServiceImp(userServiceImp);
p.add();
p.update();
p.delete();
p.query();
}
}
/**
* 執(zhí)行結(jié)果:
* 日志:add語句執(zhí)行了
* 添加了一條數(shù)據(jù)
* 日志:update語句執(zhí)行了
* 修改了一條數(shù)據(jù)
* 日志:delete語句執(zhí)行了
* 刪除了一條數(shù)據(jù)
* 日志:add語句執(zhí)行了
* 查詢了一條數(shù)據(jù)
*/接口:
package com.proxyPattern. autoProxy;
/**
* @author wang
* @version 1.0
* @packageName com.proxyPattern.staticProxy2
* @className UserService
* @date 2021/12/27 17:54
* @Description 服務(wù)接口
*/
public interface UserService {
void add();
void delete();
void update();
void query();
}動態(tài)代理類,這個幾乎可以做一個工具類使用,因為格式固定
package com.proxyPattern.autoProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author wang
* @version 1.0
* @packageName com.proxyPattern.autoProxy
* @className ProxyInvocationHandler
* @date 2021/12/27 19:33
* @Description 動態(tài)代理類
*/
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
/**
* @Date 2021/12/27 19:36
* @Param
* @Return Object
* @MetodName getProxy
* @Author wang
* @Description 生成得到代理類
*/
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
/**
* @Date 2021/12/27 19:34
* @Param
* @param proxy
* @param method
* @param args
* @Return Object
* @MetodName invoke
* @Author wang
* @Description 處理代理實例,并返回結(jié)果
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log(String message) {
System.out.println("日志:" + message + "語句執(zhí)行了" );
}
}客戶端測試類:
package com.proxyPattern.autoProxy;
/**
* @author wang
* @version 1.0
* @packageName com.proxyPattern.staticProxy2
* @className Customer
* @date 2021/12/27 18:00
* @Description 客戶終端測試類
*/
public class Customer {
public static void main(String[] args) {
//真實角色
UserService userService = new UserServiceImp();
//代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//動態(tài)設(shè)置代理的對象
pih.setTarget(userService);
//動態(tài)生成代理類
UserService proxy = (UserService) pih.getProxy();
proxy.query();
proxy.update();
}
}
/**
* 日志:query語句執(zhí)行了
* 查詢了一條數(shù)據(jù)
* 日志:update語句執(zhí)行了
* 修改了一條數(shù)據(jù)
*/可以看到我們這里可以更方便的去獲取代理類了,只需要將動態(tài)設(shè)置代理類那里的對象改一下,就可以去代理別的類。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
使用JSCH框架通過跳轉(zhuǎn)機訪問其他節(jié)點的方法
下面小編就為大家分享一篇使用JSCH框架通過跳轉(zhuǎn)機訪問其他節(jié)點的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12
java對xml節(jié)點屬性的增刪改查實現(xiàn)方法
下面小編就為大家?guī)硪黄猨ava對xml節(jié)點屬性的增刪改查實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-10-10
jdk17?SpringBoot?JPA集成多數(shù)據(jù)庫的示例詳解
這篇文章主要介紹了jdk17?SpringBoot?JPA集成多數(shù)據(jù)庫的示例代碼,包括配置類、請求攔截器、線程上下文等相關(guān)知識,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-08-08

