代理模式
转自 http://blog.csdn.net/briblue/article/details/73928350
参考:https://www.jianshu.com/p/58759fef38b8
一、静态代理
package com.proxy.test; /** * 首先得有一个接口,通用的接口是代理模式实现的基础。这个接口我们命名为 Movie,代表电影播放的能力 * @author Yuanjingkun * */ public interface Movie { void play(); }
package com.proxy.test; /** * 真正实现 Movie接口的类,这个表示真正的影片。它实现了 Movie 接口,play() 方法调用时,影片就开始播放 * @author Yuanjingkun * */ public class RealMovie implements Movie { @Override public void play() { System.out.println("您正在观看电影 《肖申克的救赎》"); } }
package com.proxy.test; /** * 只是实现接口的代理类,Cinema 就是 Proxy 代理对象,它有一个 play() 方法。不过调用 play() 方法时,它进行了一些相关利益的处理,那就是广告。 * @author Yuanjingkun * */ public class Cinema implements Movie { RealMovie movie; public Cinema(RealMovie movie) { this.movie = movie; } @Override public void play() { guanggao(true); movie.play(); guanggao(false); } public void guanggao(boolean isStart){ if ( isStart ) { System.out.println("电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!"); } else { System.out.println("电影马上结束了,爆米花、可乐、口香糖9.8折,买回家吃吧!"); } } }
package com.proxy.test; /** * @author Yuanjingkun * */ public class ProxyTest { public static void main(String[] args) { RealMovie realmovie = new RealMovie(); Movie movie = new Cinema(realmovie); movie.play(); } }
结果:
电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!
您正在观看电影 《肖申克的救赎》
电影马上结束了,爆米花、可乐、口香糖9.8折,买回家吃吧!
现在可以看到,代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。
二 、动态代理
package com.frank.test; public interface SellWine { /** * 卖酒 */ void maiJiu(); }
package com.frank.test; public interface SellCigarette { /** * 卖烟 */ void maiYan(); }
package com.frank.test; public class MaotaiJiu implements SellWine{ @Override public void maiJiu() { System.out.println("我卖的是茅台酒"); } }
package com.frank.test; public class Wuliangye implements SellWine{ @Override public void maiJiu() { System.out.println("我卖的是五粮液"); } }
package com.frank.test; public class Furongwang implements SellCigarette{ @Override public void maiYan() { // TODO Auto-generated method stub System.out.println("售卖的是芙蓉王,可以扫码查证"); } }
package com.frank.test; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class GuitaiA implements InvocationHandler{ private Object pinpai; public GuitaiA(Object pinpai){ this.pinpai = pinpai; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("销售开始 柜台是:"+this.getClass().getSimpleName()); method.invoke(pinpai, args); System.out.println("销售结束"); return null; } }
package com.frank.test; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { MaotaiJiu maotaijiu = new MaotaiJiu(); Wuliangye wuliangye = new Wuliangye(); Furongwang furongwang = new Furongwang(); InvocationHandler jingxiao1 = new GuitaiA(maotaijiu); InvocationHandler jingxiao2 = new GuitaiA(wuliangye); InvocationHandler jingxiao3 = new GuitaiA(furongwang); SellWine dynamicProxyMaotai = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(), MaotaiJiu.class.getInterfaces(), jingxiao1); SellWine dynamicProxyWuliangye = (SellWine) Proxy.newProxyInstance(Wuliangye.class.getClassLoader(), Wuliangye.class.getInterfaces(), jingxiao2); SellCigarette dynamicProxyFurongwang = (SellCigarette) Proxy.newProxyInstance(Furongwang.class.getClassLoader(), Furongwang.class.getInterfaces(),jingxiao3); dynamicProxyMaotai.maiJiu(); dynamicProxyWuliangye.maiJiu(); dynamicProxyFurongwang.maiYan(); System.out.println(dynamicProxyMaotai.getClass().getName()); } }
结果:
销售开始 柜台是:GuitaiA
我卖的是茅台酒
销售结束
销售开始 柜台是:GuitaiA
我卖的是五粮液
销售结束
销售开始 柜台是:GuitaiA
售卖的是芙蓉王,可以扫码查证
销售结束
com.sun.proxy.$Proxy0
红框中 $Proxy0
就是通过 Proxy 动态生成的。 $Proxy0
实现了要代理的接口。 $Proxy0
通过调用 InvocationHandler
来执行任务。
总结
- 代理分为静态代理和动态代理两种。
- 静态代理,代理类需要自己编写代码写成。
- 动态代理,代理类通过 Proxy.newInstance() 方法生成。
- 不管是静态代理还是动态代理,代理与被代理者都要实现两样接口,它们的实质是面向接口编程。
- 静态代理和动态代理的区别是在于要不要开发者自己定义 Proxy 类。
- 动态代理通过 Proxy 动态生成 proxy class,但是它也指定了一个 InvocationHandler 的实现类。
- 代理模式本质上的目的是为了增强现有代码的功能。