介紹
在代理模式(Proxy Pattern)中,一個類代表另一個類的功能。這種類型的設計模式屬於結構型模式。在代理模式中,我們創建具有現有對象的對象,以便向外提供功能接口
意圖
:爲其他對象提供一種代理以控制對這個對象的訪問
主要解決
:在直接訪問對象時帶來的問題,比如說:要訪問的對象在遠程的機器上。在面向對象系統中,有些對象由於某些原因(比如對象創建開銷大,或者某些操作需要安全控制,或者需要進程外的範文),直接訪問會給使用者或者系統結構帶來很多麻煩,我們可以在訪問此對象時加上一個對此對象的訪問層。
何時使用
:想在訪問一個類時做一些控制
如何解決
:增加中間層
靜態代理
抽象角色
:一般會使用接口或抽象類來解決
真實角色
:被代理的角色
代理角色
:代理真實角色,代理真實角色後,我們一般會做一些附屬操作
客戶
:訪問代理對象的人
以找中介租房子爲例
租房接口
package GProxy.stactic;
/**
* @Author Zhou jian
* @Date 2020 ${month} 2020/7/2 0002 14:03
* 租房
*/
public interface Rent {
public void rent();
}
房東出租房屋
package GProxy.stactic;
/**
* @Author Zhou jian
* @Date 2020 ${month} 2020/7/2 0002 14:03
* 房東
*/
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房東要出租房子");
}
}
中介
package GProxy.stactic;
/**
* @Author Zhou jian
* @Date 2020 ${month} 2020/7/2 0002 14:04
中介角色:
*/
public class Proxy implements Rent {
//將房東組合進來
private Host host;
public Proxy(Host host) {
this.host = host;
}
//看房
public void seeHouse(){
System.out.println("中介帶你看房");
}
public void fare(){
System.out.println("收中介非");
}
@Override
public void rent() {
seeHouse();
host.rent();
fare();
}
}
優缺點
優點
- 可以使得真實角色的操作更加純粹!不用關注一些公共的業務
- 公共也就交給代理角色,實現業務的分工
- 公共業務發生擴展的時候,方便集中管理
動態代理
- 動態代理和靜態代理角色一樣
- 動態代理的代理類是動態生成的,不是我們直接寫好的
- 動態代理分爲兩大類:基於接口的動態代理,基於類的動態代理
基於接口---JDK動態代理
基於類:CGLIB
java字節碼實現:javasist
基於JDK實現動態代理
相關的類與接口
Proxy
InvocationHandler
Proxy類
//通過這個方法返回被代理的對象
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
InvocationHandler接口
//在InvocationHandler中進行方法的增強
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
JDK動態代理實現房屋租賃
租賃接口
package GProxy.dynamic;
/**
* @Author Zhou jian
* @Date 2020 ${month} 2020/7/2 0002 14:03
* 租房
*/
public interface Rent {
public void rent();
}
package GProxy.dynamic;
/**
* @Author Zhou jian
* @Date 2020 ${month} 2020/7/2 0002 14:03
* 房東
*/
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房東要出租房子");
}
}
增強的對象
package GProxy.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Author Zhou jian
* @Date 2020 ${month} 2020/7/2 0002 15:53
*/
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public ProxyInvocationHandler(Rent rent) {
this.rent = rent;
}
public ProxyInvocationHandler() {
}
public Rent getRent() {
return rent;
}
public void setRent(Rent rent) {
this.rent = rent;
}
//生成得到的代理類
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),
this);
}
//處理代理實例,並放回結果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//動態代理的本質:就是使用反射機制實現
System.out.println("看房子");
Object result = method.invoke(rent,args);
return result;
}
}
客戶端調用
package GProxy.dynamic;
import com.sun.org.apache.regexp.internal.RE;
/**
* @Author Zhou jian
* @Date 2020 ${month} 2020/7/2 0002 15:57
*/
public class Client {
public static void main(String[] args) {
//真實角色
Host host = new Host();
//代理角色
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
//通過調用程序處理角色來處理我們要調用的街路口對象
proxyInvocationHandler.setRent(host);
Rent proxy = (Rent)proxyInvocationHandler.getProxy();//這裏的proxy就是通過動態代理生成的,我們並沒有寫
proxy.rent();
}
}