JAVA设计模式 5【结构型】代理模式的理解与使用

栏目: IT技术 · 发布时间: 4年前

内容简介:今天要开始我们结构型设计模式又分为前者使用对象的

今天要开始我们 结构型 设计模式的学习,设计模式源于生活,还是希望能通过生活中的一些小栗子去理解学习它,而不是为了学习而学习这些东西。

结构型设计模式

结构型 设计模式 又分为

  • 类 结构型
  • 对象 结构型

前者使用对象的 继承机制 来组织对象和类

后者采用 组合聚合 的方式来组合对象。

代理模式 Proxy

理解 代理一词 代理表达的是:为某个对象提供一种代理,用于控制该对象的访问,让客户端间接的访问该对象,从而限制、或者增强源对象的一些特性。

举个栗子

JAVA设计模式 5【结构型】代理模式的理解与使用

从国内 科学SW ,访问谷歌查阅一些资料的时候,我们肯定务必会借助一些 代理器 也就是通常所说的 VPN ,代理的服务器可以帮助我们完成这些操作。

静态代理

画个图理解一下

JAVA设计模式 5【结构型】代理模式的理解与使用

需要说明的地方有:

  • 抽象父类或者接口:定义了这个代理可以代理的方法。比如定义了一个 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()

老衲画个图

JAVA设计模式 5【结构型】代理模式的理解与使用

这样就好理解多了,代理工厂需要一个代理类、以及这个代理类的增强方法(处理器),通过代理工厂生成的代理对象,实现对对象的增强处理。

动态代理的总结

  • 代理类不需要实现接口,但是具体对象还是需要实现接口。

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【结构型】代理模式的理解与使用


以上所述就是小编给大家介绍的《JAVA设计模式 5【结构型】代理模式的理解与使用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

MATLAB高效编程技巧与应用

MATLAB高效编程技巧与应用

吴鹏 / 北京航空航天大学 / 2010-6 / 39.00元

《MATLAB高效编程技巧与应用:25个案例分析》是作者八年MATLAB使用经验的总结,精心设计的所有案例均来自于国内各大MATLAB技术论坛网友的切身需求,其中不少案例涉及的内容和求解方法在国内现已出版的MATLAB书籍中鲜有介绍。 《MATLAB高效编程技巧与应用:25个案例分析》首先针对MATLAB新版本特有的一些编程思想、高效的编程方法、新技术进行了较为详细的讨论,在此基础上,以大量......一起来看看 《MATLAB高效编程技巧与应用》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码