一.代理模式
什么是代理模式?
控制访问: A对象不能直接调用B对象,通过创建C对象去调用B对象,那么C是B的代理对象,B是C的目标对象。
功能增强: 在C对象调用B对象的方法的同时,又在其中加入新的功能代码,使得原方法增强,也叫包了一层。
场景模拟:
小韭想买房要找中介,因为小韭只想付钱和拿房产证,其他买房复杂的事情交给中介去办。房产商想要完成交易,就要去找小韭的代理对象中介,最终的目标对象就是小韭。
中介接口
public interface BuyHouse {
//付钱
void pay();
//拿房产证
void getLicense();
}
买房人接口
public class BuyHousePeople implements BuyHouse {
private String name;
private Building building;
public String getName() {
return name;
}
public Building getBuilding() {
return building;
}
public BuyHousePeople(String name, Building building) {
this.name = name;
this.building = building;
}
public void pay() {
System.out.println(name + "给" + building.getName() + "楼盘付钱");
}
public void getLicense() {
System.out.println("户主:" + name + "房产证上的楼盘地址:" + building.getAddress());
}
}
中介
public class Proxy implements BuyHouse {
private BuyHousePeople buyHousePeople;
public Proxy(Building building,String name) {
buyHousePeople = new BuyHousePeople(name,building);
}
public void pay() {
System.out.println("中介开车接"+buyHousePeople.getName()+"去"+buyHousePeople.getBuilding().getAddress());
buyHousePeople.pay();
}
public void getLicense() {
System.out.println("中介帮"+buyHousePeople.getName()+"整理资料给开发商");
buyHousePeople.getLicense();
}
}
开发商
public class Building {
private String name;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
开始交易
public class StartBuyHouse {
public static void main(String[] args) {
Building building = new Building();
building.setName("山水·拾光");
building.setAddress("长安航天城");
Building building2 = new Building();
building2.setName("万科金域华府");
building2.setAddress("经开大道");
Proxy proxy = new Proxy(building,"小韭");
proxy.pay();
proxy.getLicense();
Proxy proxy2 = new Proxy(building2,"小李");
proxy2.pay();
proxy2.getLicense();
}
}
输出
中介开车接小韭去长安航天城
小韭给山水·拾光楼盘付钱
中介帮小韭整理资料给开发商
户主:小韭房产证上的楼盘地址:长安航天城
中介开车接小李去经开大道
小李给万科金域华府楼盘付钱
中介帮小李整理资料给开发商
户主:小李房产证上的楼盘地址:经开大道
上面的代码我们能看出:
1. 在买房人(目标对象)在不自我学习买房知识的情况下(不改变原本代码),中介(代理对象)的使用使得买房人(目标对象)能力得到拓展,并完成买房。
2. 以后不管谁买房,只需要找中介(相同的能力代码抽取出来使得代码复用增强)。
看到这里有没有感觉似曾熟悉,就是日志打印的时候是不是不需要每个方法中都加日志打印的代码? 判断接口权限的时候是不是不需要每个接口去写权限校验代码?这个就是AOP,面向切面编程,一种横向的代码增强模式,但是AOP使用的是动态代理模式。
二.动态代理
为什么要动态代理?
如果项目中的目标类比较多,那随之而来的代理类也会逐渐增多。
一旦接口中的方法有改动(返回值,参数类型等)都需要目标类和代理类的改变。
什么是动态代理?
为了解决上述静态代理缺点,在Java运行过程中,利用反射动态的创建目标对象,并且完成目标对象的调用以及增强的方式,叫动态代理。
我们可以改造上面的例子使用JDK自带动态代理:
public class DynamicProxy implements InvocationHandler {
private Object object;
public Object get(Object o){
this.object=o;
return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
if (name.equals("pay")){
System.out.println("中介帮忙pay..");
}
if (name.equals("getLicense")){
System.out.println("中介帮忙getLicense..");
}
return method.invoke(object,args);
}
public static void main(String[] args) {
BuyHousePeople buyHousePeople = new BuyHousePeople("小韭", new Building("山水·拾光", "长安航天城"));
BuyHouse buyHouse = (BuyHouse)new DynamicProxy().get(buyHousePeople);
buyHouse.pay();
buyHouse.getLicense();
BuyHousePeople buyHousePeople1 = new BuyHousePeople("小韭", new Building("科金域华府", "经开大道"));
BuyHouse buyHouse1 = (BuyHouse)new DynamicProxy().get(buyHousePeople1);
buyHouse1.pay();
buyHouse1.getLicense();
}
}
输出:
中介帮忙getLicense..
户主:小韭房产证上的楼盘地址:长安航天城
中介帮忙pay..
小韭给科金域华府楼盘付钱
中介帮忙getLicense..
户主:小韭房产证上的楼盘地址:经开大道