Java设计模式——代理模式
有个故事很长很长............................然后就没了
代理模式
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
意图:为其他对象提供一种代理以控制对这个对象的访问。
主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
——摘自菜鸟教程
简单的静态代理:
下面代码演示:
背景:玛蒂达收定金,莱昂动手,玛蒂达收余款,然后对话两句。根据背景编写代码
创建接口杀手职业
/** * 杀手职业 * * @author wanghao * @version C10 2018年5月10日 * @since SDP V300R003C10 */ interface Killer { void kill(); }
创建莱昂杀手类
/** * 杀手:莱昂登场 * * @author wanghao * @version C10 2018年5月10日 * @since SDP V300R003C10 */ class Léon implements Killer { @Override public void kill() { System.out.println("莱昂杀了一只鸡"); } public void léonSay(){ System.out.println("莱昂:总是如此"); } }
创建代理类:收钱人玛蒂达
/** * 创建代理类:收钱人玛蒂达 * * @author wanghao * @version C10 2018年5月10日 * @since SDP V300R003C10 */ class Mathilda implements Killer { private Léon léon; Mathilda() { if (léon == null) { léon = new Léon(); } } @Override public void kill() { getDeposit(); léon.kill(); getBalance(); mathildaSay(); léon.léonSay(); } public void getDeposit() { System.out.println("收取定金"); } public void getBalance() { System.out.println("收取余款"); } public void mathildaSay() { System.out.println("\n玛蒂达:人生总是这么痛苦吗?还是只有小时候是这样"); } }
然后然后然后然后:简单的测试类
public static void main(String[] args) { Killer killer = new Mathilda(); killer.kill(); }
面向用户的代码就是这个,你能看出来是谁杀了人吗?看下执行结果

代理模式就是为了更好的隐藏被代理者,然后代理者可以内部控制被代理者。下面画张丑图可以意会一下:

代理模式与之前装饰者模式的区别也在于,代理模式隐藏代理者并且控制代理者,装饰者模式却是对被装饰者的一个扩展或者增强。
可点击进入本人分享的装饰者模式 Java设计模式——装饰者模式
说到代理就要说说静态代理和动态代理了,上面是静态代理,简单的可以更好理解这种模式,然后下面说下动态代理,动态代理举出两个动态代理的例子吧:
JDK代理:
还是使用上面的杀手职业类和杀手莱昂类。然后写一个动态代理工厂类
注:JDK动态代理,被代理类需要实现接口,这是JDK动态代理的要求。
/** * 简化版动态代理 * * @author wanghao * @version C10 2018年5月10日 * @since SDP V300R003C10 */ class ProxyFactory { public static <T> Object getProxy(Class<T> t) { return Proxy .newProxyInstance( t.getClassLoader(), t.getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("收取定金"); Object result = method.invoke(t.newInstance(), args); System.out.println("收取全款"); return result; } }); } }
因为想写简介,就没有持有目标对象了。测试代码如下:
Killer killer = (Killer)ProxyFactory.getProxy(Léon.class); killer.kill();
不是我懒,真的测试只需要两句代码就好了,看打印吧:

如果觉得上面动态代理工厂不容易理解,那就拆分了上面工厂代理代码,仿照静态的模板写一个动态代理工厂如下:
/** * 模板化JDK动态代理模式 * * @author wanghao * @version C10 2018年5月10日 * @since SDP V300R003C10 */ class ProxyFactory2<T> { //持有目标对象 private T t; //因为不知道代理者是谁,所以需要传入代理者 ProxyFactory2(T t){ this.t = t; } //方法实现 public Object getProxy() { return Proxy .newProxyInstance( t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("收取定金"); Object result = method.invoke(t, args); System.out.println("收取全款"); return result; } }); } }
是不是更好理解了呢,
Cglib代理:
cglib代理,又称子类代理,跟静态代理和JDK代理最大的区别就是静态与JDK都要实现接口,而cglib却不需要实现接口,创建的是目标代理的子类,代理目标对象的。
cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
注意:
- 因为是子类代理,所以不能把目标类声明为final,因为加了final之后就不能被继承了。
- 目标对象被代理的方法是静态或者final的则不会被代理,这方面可自行去看多态。
代码如下,首先创建一个不实现接口的莱昂杀手,当然也可以实现接口
/** * 杀手:莱昂登场 * 不实现接口的莱昂 * * @author wanghao * @version C10 2018年5月10日 * @since SDP V300R003C10 */ class Léon { public void kill() { System.out.println("莱昂杀了一只鸡"); } }
然后创建代理工厂类:
因为我用的Spring的包,所以引入的是Spring里面的Cglib代理包如下引入:
import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy;
代码如下:
/** * Cglib动态代理工厂类 * * @author wanghao * @version C10 2018年5月10日 * @param <T> * @since SDP V300R003C10 */ class CglibProxyFactory<T> implements MethodInterceptor { //被代理或者目标对象 private T t; //传入被代理对象 CglibProxyFactory (T t){ this.t = t; } //给被代理者创建一个代理对象 public T getProxyInstance(){ //1.工具类 Enhancer en = new Enhancer(); //2.设置父类 en.setSuperclass(t.getClass()); //3.设置回调函数 en.setCallback(this); //4.创建子类(代理对象) return (T)en.create(); } @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("Cglib动态代理:收取定金"); Object result = method.invoke(t, args); System.out.println("Cglib动态代理:收取全款"); return result; } }
测试类如下:
好吧,依然两句测试类,本篇文章测试类好像都是两句,哈哈。
Léon léonProxy = new CglibProxyFactory<Léon>(new Léon()).getProxyInstance(); léonProxy.kill();
下面看测试结果吧:

这就是Cglib动态代理。
代理模式到这里就完结了,自己理解也是这些。
代理模式与装饰者模式的区别
再次说一下代理模式与装饰者模式的区别,免得大家混淆,因为目标不同所以就有不同的实现
1. 代理模式隐藏代理者并且控制代理者,
2. 装饰者模式却是对被装饰者的一个扩展或者增强。


浙公网安备 33010602011771号