内容简介:今天要开始我们结构型设计模式又分为前者使用对象的
今天要开始我们 结构型
设计模式的学习,设计模式源于生活,还是希望能通过生活中的一些小栗子去理解学习它,而不是为了学习而学习这些东西。
结构型设计模式
结构型 设计模式 又分为
- 类 结构型
- 对象 结构型
前者使用对象的 继承机制
来组织对象和类
后者采用 组合聚合
的方式来组合对象。
代理模式 Proxy
理解 代理一词
代理表达的是:为某个对象提供一种代理,用于控制该对象的访问,让客户端间接的访问该对象,从而限制、或者增强源对象的一些特性。
举个栗子
从国内 科学SW
,访问谷歌查阅一些资料的时候,我们肯定务必会借助一些 代理器
也就是通常所说的 VPN
,代理的服务器可以帮助我们完成这些操作。
静态代理
画个图理解一下
需要说明的地方有:
- 抽象父类或者接口:定义了这个代理可以代理的方法。比如定义了一个
SearchSubject
实现它的子类必须要实现对应的search()
方法。
/** * 抽象主题,可以进行搜索 */ public abstract class SearchSubject { /** * 可以进行搜索的操作 */ public abstract void search(); }
- 真实对象:真实对象也就是具体将要
被代理的方法
,这个真实对象的方法我们要通过代理类间接的去访问
。
众所周知,国内访问不到Google,需要代理才行。
public class Google extends SearchSubject { @Override public void search() { System.out.println("Google 搜索引擎"); } }
- 代理类:也就是VPN ,帮助我们访问
真实对象
的某些方法,并且还可以做一些增强。比如在访问真实对象之前
做一些事情,之后做一些事情。
/** * VPN 代理 * 静态代理也需要实现抽象主题 */ public class VPNProxy extends SearchSubject { /** * 含有真实主题 */ private Google google; @Override public void search() { if (null == google) { google = new Google(); } this.before(); /** * 调用真实对象的方法 */ google.search(); this.after(); } /** * 增强方法 */ public void before() { System.out.println("VPN 开始执行。。。"); } public void after() { System.out.println("VPN 结束执行"); } }
执行调用代理
VPNProxy proxy = new VPNProxy(); proxy.search(); ------------------ VPN 开始执行。。。 Google 搜索引擎 VPN 结束执行
以上就是我们要学习的第一种代理方式: 静态代理
动态代理
假设我们还需要代理一个对象呢?比如 必应
假设 必应搜索
我们国内访问不到,必须使用代理的话,是不是又得重新创建两个对象
必应搜索 必应搜索的代理
这就不利于我们系统的扩展性,假设有很多需要代理的,那岂不是写一大堆。
因此,动态代理由此而生。
这里我们使用JDK 提供的动态代理
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h){}
- ClassLoader 类加载器
- interfaces 加载的接口
- InvocationHandler 增强处理器以及调用代理的类
创建一个可供实现的搜索接口
/** * 搜索接口 */ public interface SearchInterface { String search(); }
谷歌搜索引擎实现了这个接口,并且将名称作为返回值返回。
public class GoogleSearch implements SearchInterface { @Override public String search() { System.out.println("Google 搜索引擎"); return "Google"; } }
创建一个搜索增强器,并且创建了两个方法的增强,在调用代理之前和之后,都加入了一些方法。
/** * 搜索处理器 */ public class SearchHandler implements InvocationHandler { private void before() { System.out.println("handler start"); } private void after() { System.out.println("handler stop"); } private SearchInterface obj; public SearchHandler(SearchInterface obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { this.before(); /** * 执行代理方法 */ Object result = method.invoke(obj, args); System.out.println("result=" + result.toString()); this.after(); return result; } }
创建一个动态代理工厂,将我们需要代理的接口传入,并且传入接口的处理类,即可实现接口的增强处理。
/** * 动态代理工厂 */ public class ProxyFactory { /** * 目标对象 */ private SearchInterface object; private InvocationHandler handler; public ProxyFactory(SearchInterface obj, InvocationHandler handler) { this.object = obj; this.handler = handler; } /** * 获取代理对象 * @return */ public Object getProxyObj() { ClassLoader classLoader = object.getClass().getClassLoader(); Class<?>[] interfaces = object.getClass().getInterfaces(); return Proxy.newProxyInstance(classLoader, interfaces, handler); } }
创建一个具体的接口对象,传入我们的代理工厂,并且将其处理器也同时传入,我们就可以得到一个代理对象。
SearchInterface search = new GoogleSearch(); System.out.println("1id=" + search); InvocationHandler handler = new SearchHandler(search); ProxyFactory factory = new ProxyFactory(search, handler); SearchInterface google = (SearchInterface) factory.getProxyObj(); System.out.println("2id=" + google); google.search(); ----------------- 1id=impl.GoogleSearch@1b6d3586 handler start result=impl.GoogleSearch@1b6d3586 handler stop 2id=impl.GoogleSearch@1b6d3586 handler start Google 搜索引擎 result=Google handler stop
从上面的代码我们发现:
- 代理的对象与我们创建的对象有所不同
- 在生成代理对象的时候、已经执行了一遍invoke() 方法
- 通过代理对象调用具体方法的时候也执行了一遍invoke()
老衲画个图
这样就好理解多了,代理工厂需要一个代理类、以及这个代理类的增强方法(处理器),通过代理工厂生成的代理对象,实现对对象的增强处理。
动态代理的总结
- 代理类不需要实现接口,但是具体对象还是需要实现接口。
Cglib代理
上面两种代理,都是需要代理类、或者是具体的目标对象实现某个接口的基础上出现的,假设没有这个接口的显示,我只想在某个具体的对象上加入增强的话,如何实现呢?
Cglib代理又被称作 子类代理
,就是代理一个具体的子类
因为Spring 已经引入了相关的Cglib 的依赖,我们直接在Spring 的环境下进行测试。
创建一个具体的子类。没有实现任何的接口
public class BingSearch { public void search() { System.out.println("必应搜索。。。"); } }
创建类实现一个方法拦截器,其实名字就是这样叫的。我们的代理对象,是通过 工具 类拿出来的。
public class ProxyFactory implements MethodInterceptor { //维护目标对象 private Object target; public ProxyFactory(Object target) { this.target = target; } private void before() { System.out.println("代理类前置处理。。"); } private void after() { System.out.println("代理类后置处理。。"); } public Object getProxy() { //1.工具类 Enhancer en = new Enhancer(); //2.设置父类 en.setSuperclass(target.getClass()); //3.设置回调函数 en.setCallback(this); //4.创建子类(代理对象) return en.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { /** * 执行方法 */ this.before(); Object result = method.invoke(target, objects); this.after(); return result; } }
在main 方法对一个具体的类进行增强代理。
public static void main(String[] args) { ProxyFactory proxyFactory = new ProxyFactory(new BingSearch()); BingSearch bing = (BingSearch) proxyFactory.getProxy(); bing.search(); } --------- 代理类前置处理。。 必应搜索。。。 代理类后置处理。。
小结
本节,将我们最常用的两种代理模式进行了一些讲解,其实最重要的是 JDK动态代理
和 Cglib 具体方法代理增强
。因为大家已经拥抱Spring 的怀抱了,这两种代理还是很重要的,Spring的AOP 切面也是一种基于动态代理的方式实现。非常好用,在Spring 声明式事务当中,一个注解即可搞定许多冗余的编程式事务,这无不归功于 强大的 动态代理
鸣谢&参考
https://www.cnblogs.com/leeego-123/p/10995975.html
代码
https://gitee.com/mrc1999/Dev-Examples
欢迎关注
以上所述就是小编给大家介绍的《JAVA设计模式 5【结构型】代理模式的理解与使用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
MATLAB高效编程技巧与应用
吴鹏 / 北京航空航天大学 / 2010-6 / 39.00元
《MATLAB高效编程技巧与应用:25个案例分析》是作者八年MATLAB使用经验的总结,精心设计的所有案例均来自于国内各大MATLAB技术论坛网友的切身需求,其中不少案例涉及的内容和求解方法在国内现已出版的MATLAB书籍中鲜有介绍。 《MATLAB高效编程技巧与应用:25个案例分析》首先针对MATLAB新版本特有的一些编程思想、高效的编程方法、新技术进行了较为详细的讨论,在此基础上,以大量......一起来看看 《MATLAB高效编程技巧与应用》 这本书的介绍吧!