Java学设计模式之代理模式
一、代理模式概念
1.1 什么是代理模式
Proxy Pattern,代理模式是指为其他对象提供一种代理,以控制对这个对象的访问,代理对象在客户端,服务端以及目标对象之间起到中介作用。并且是属于一种结构型模式
1.2 代理模式架构示意图
-
静态代理模式
-
动态代理模式
动态代理没有代理类,可以直接通过反射包下的接口和方法,会通过外部的传参来确定成为哪个类的动态代理对象。并且会通过这个invoke方法来获取目标类对象里面的方法,然后获取到结果之后对这个类进行一个功能的增强。
1.3 代理模式的作用
- 功能增强,可以在原有的功能上能可以增加额外的功能
- 控制访问,可以通过这个代理类来实现能不能到访问这个目标类
二、静态代理模式代码
2.1 公共接口类
public interface PhoneSell {
/**
* 销售方法
*
* @param amount 数量
* @return 价格
*/
public double sell(Double amount);
}
2.2 目标类
public class XiaoMiFactory implements PhoneSell {
/**
* 小米销售方法
*
* @param amount 数量
* @return 价格
*/
@Override
public double sell(Double amount) {
// 小米手机一台卖2000元
return 2000 * amount;
}
}
2.3 代理类
public class JingDongShop implements PhoneSell {
private XiaoMiFactory xiaoMiFactory = new XiaoMiFactory();
/**
* 京东商城销售方法
*
* @param amount 数量
* @return 价格
*/
@Override
public double sell(Double amount) {
// 获取小米工厂售价
double price = xiaoMiFactory.sell(amount);
// 京东商家也需要赚取一些差价
price = price + price * 0.1;
// 返回京东销售小米手机的价格
return price;
}
}
2.4 测试类
public class ProxyPatternTest {
public static void main(String[] args) {
JingDongShop jingDongShop = new JingDongShop();
double sell = jingDongShop.sell(1.0);
System.out.println("手机售价:" + sell);
// 输出 手机售价:2200.0
}
}
三、动态代理模式代码
3.1 公共接口类
public interface PhoneSell {
/**
* 销售方法
*
* @param amount 数量
* @return 价格
*/
public double sell(Double amount);
}
3.2 目标类
public class XiaoMiFactory implements PhoneSell {
/**
* 小米销售方法
*
* @param amount 数量
* @return 价格
*/
@Override
public double sell(Double amount) {
// 小米手机一台卖2000元
return 2000 * amount;
}
}
3.3 动态代理类
public class ProxyInvocationHandler implements InvocationHandler {
public Object target;
public ProxyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object;
//目标方法执行
//第一个是目标对象,第二个是目标参数
//这个目标对象是一个动态的,因此需要外面传入
object = method.invoke(target, args);
//在获取到这个目标方法之后,可以对这个目标方法进行一个增强功能
if (object != null) {
//外部传入这个sell的这个方法,那么执行这个方法的返回值类型为Double
Double price = (Double) object;
//手机店获取利润,功能增强
price = price + price * 0.1;
object = price;
}
return object;
}
}
3.4 测试类
public class ProxyPatternTest {
public static void main(String[] args) {
//1,创建目标对象
XiaoMiFactory xiaoMiFactory = new XiaoMiFactory();
//2,创建proxyInvocationHandler对象
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(xiaoMiFactory);
//3,创建动态代理对象
//获取目标类类加载器
ClassLoader classLoader = xiaoMiFactory.getClass().getClassLoader();
//获取类对应的接口
Class<?>[] interfaces = xiaoMiFactory.getClass().getInterfaces();
//通过反射的形式获取代理类
//强行转换成对应的接口
PhoneSell proxy = (PhoneSell) Proxy.newProxyInstance(classLoader, interfaces, proxyInvocationHandler);
//购买数量
Double sellPrice = proxy.sell(1.0);
System.out.println("手机售价:" + sellPrice);
// 输出 手机售价:2200.0
}
}
四、总结
代理模式主要分为静态代理和动态代理。
静态代理中主要有一个目标类和一个代理类,其两个类都要实现一个共同的接口,做一样的事情,代理对象主要负责转发和功能增强,其具体做事情的还是这个目标对象。静态代理不足的地方在于一个代理类只能绑定一个目标类,如果一个目标类或者多个目标类需要多个代理对象,那么就需要创建大量的代理对象,并且如果接口类里面有一点点的功能的改动,那么这个目标类和代理类就会有大量的改动。
动态代理解决了这个静态代理的问题,在要创建很多代理对象方面,通过一个动态代理对象实现。动态代理主要有jdk的动态代理和cglib的动态代理,jdk动态代理是java里面自带的库,而cglib使用的是第三方库。jdk动态代理主要是通过这个InvocationHandler接口来获取这个目标类和实现代理类的功能增强,并通过反射的方式,获取到这个代理类对象,最后通过这个代理对象获取到对应的方法。
参考资料