设计模式之代理模式

       先举个例子,来说明为什么要用代理模式。

       假如有类A,有类的实例方法,test()。现在,有一个场景是,我想要在test原来的方法前执行一些任务,在原来方法完成后再执行一些任务。那么,按照我们原来的思路,我们需要做的是,修改test()方法。这个时候还不算复杂。如果test方法被两个位置调用。一个位置需要新的test方法,另一个位置需要旧的test方法。那么,修改方案无疑将变得更加复杂。

       于是,代理模式被发现了。这种模式就是为了解决以上问题的。代理模式可以在不修改原方法的情况下,在原方法执行前后,分别添加新的任务。

       接下来,我们分享三种代理模式的实现方法。

       先假设有接口如下:

package com.syxsoa.dao;

publicinterface TestDao {

    void test(); 

}

       接口有一个实现类如下:

package com.syxsoa.dao;

publicclass TestDaoImpl implements TestDao{

    publicvoid test() {

        System.out.println("执行接口实现类");

    }
 
}

       我们要做的是,在不改变TestDaoImpl类的方法的情况下,在test方法前后分别执行一些任务。

       第一种,称之为静态代理。代码如下:

package com.syxsoa.dao;

publicclass TestDaoProxy implements TestDao{

    private TestDao testDao;      

    publicvoid test() {

        System.out.println("执行静态代理方法1");

        testDao = new TestDaoImpl();

        testDao.test();

        System.out.println("执行静态代理方法2");

    }

}

       调用方式如下:

TestDao testDao = new TestDaoProxy();

testDao.test();

       静态代理方法非常容易理解。分析代码也可知,静态代理确实能达到我们想要的效果。

       第二种,称之为动态代理。代码如下:

package com.syxsoa.dao;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

publicclass ProxyFactory {

    private Object target;

    private Class c;
  
    public ProxyFactory(Object target){

        this.target = target;

        this.c = target.getClass();

    }


    public Object getProxyInstance(){

        return Proxy.newProxyInstance(

                c.getClassLoader(), c.getInterfaces(),

                new InvocationHandler(){

 

                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        System.out.println("执行动态代理方法1");

                        Object re = method.invoke(target, args);

                        System.out.println("执行动态代理方法2");

                        returnre;

                    }

                   

                }

        );

    }
 
}

       调用方法如下:

TestDao testDao1 = (TestDao) new ProxyFactory(new TestDaoImpl()).getProxyInstance();

testDao1.test();

       动态代理的核心方法就是Proxy类的newProxyInstance方法。Proxy是Java反射库中的一个类。通过观察该类的原代码,很容易就会发现,动态代理可以成功的关键是利用了反射。如果对这部分的具体实现原理感兴趣,可以关注本博客的后续文章。

       对比静态代理和动态代理可以发现,静态代理类需要和被代理类实现同一个接口,动态代理类则不需要。这就意味着,如果有某些同类型的类,我们要在这些类的前后执行相同的任务,那么,无疑用动态代理类更加明智。虽然动态代理类由于使用反射,有效率上的牺牲,但是,这种牺牲带来的价值是远大于牺牲的。

       通过观察我们还发现,静态代理和动态代理能够实现的前提是,被代理类继承了一个接口。那么,如果某个类没有继承接口,或者说,不依赖其接口,能否实现代理模式呢?

       当然可以,接下来,我们介绍一种Cglib模式。这种模式是Spring中采用的。因此,我们实现这种模式也需要依赖于spring-core包。

       第三种,Cglib模式。代码如下:

package com.syxsoa.dao;
 
import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;

import org.springframework.cglib.proxy.MethodInterceptor;

import org.springframework.cglib.proxy.MethodProxy;

publicclass SpringTestProxy implements MethodInterceptor{
 
    private Object target; 

    public SpringTestProxy(Object target){

        this.target = target;

    }

    public Object getProxyInstance(){

        Enhancer en = new Enhancer();

        en.setSuperclass(target.getClass());

        en.setCallback(this);

        returnen.create();

    }

    public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {

        System.out.println("执行Cglib动态代理方法1");

        Object re = arg1.invoke(target, arg2);

        System.out.println("执行Cglib动态代理方法2");

        returnre;

    }

}

       调用方法如下:

TestDaoImpl testDaoImpl = (TestDaoImpl)new SpringTestProxy(new TestDaoImpl()).getProxyInstance();

testDaoImpl.test();

       观察发现,Cglib无论是在代理类的实现还是调用时,都只使用了TestDaoImpl类,而没有使用其接口TestDao。这也就是说,Cglib这种方法,对于任何类都可以轻易的写出其代理类,无论目标类是否继承了某个接口。这种方式无疑更加灵活一些。

       理解一种设计模式的核心在于为什么要使用这种设计模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值