设计模式之代理模式总结

代理模式目前我已知的实现有三种:静态代理、动态代理、Cglib代理,本文对着三种做一个简单总结

定义

代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法

与装饰器模式的区别

乍一看上面的定义,嘿,增强额外的功能操作扩展目标对象,这不是装饰者模式干的事么?其实不然,装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对象的访问。换句话 说,用代理模式,代理类可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。而当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。所以本质是不同的,就好像我扔给你代理,连创建都让你代理,其他人来访问我的时候你都给我处理好。而装饰器模式就像一个只穿着内衣的男人,用装饰器模式,穿上一件衣服,变帅了。

举例

静态代理

代理在我们生活中随处可见,经常见到的就是代购,这个例子应该被各种代理模式文章用烂了吧,但是好的例子就是这样。接下来我就会拿着个举例子,代购需要持有对商家的购买能力(这里以代购鞋子为例),当用户来访问代购的时候,能够给予购买功能。
所以先创建一个代购的接口类

/**
 * 代购接口
 */
public interface Procurement {

    void purchase();
}

创建代购子类


public class ShoeProcurement implements Procurement {
    public void purchase() {
        System.out.println("----已经购买了商品!----");
    }
}

创建代理对象,静态代理

/**
 * 静态代理会在初始化的时候创建好代理的类
 */
public class ShoeProcurementProxy implements Procurement{

    private Procurement target;
    public ShoeProcurementProxy (){
        target=new ShoeProcurement();//创建代理类
    }

    public void purchase() {

        target.purchase();//执行代理对象的方法(购买)

    }
}

使用

Procurement  mProcurement = new ProcurementProxy ();
mProcurement . purchase();

可以看的出来很简单,隐藏了具体的实现类,客户都不知道你是用的哪个具体类来执行的购买方法,对于客户来说他只需要结果。而且我还可以在代理类中加些功能,使之达到功能扩展又不修改原子类的效果。比如加一个鞋子包装功能,加一个包邮之类的。
但是这种也是有缺点的,就是作为一个有志向的代购,我的业务怎么能停留在代购鞋子上呢,我还要能代购包包,衣服,化妆品等等。那么问题来了,使用静态代理的话每增加一种代购就得增加相应的代理类,类太多,同时,一旦接口增加方法,目标对象与代理对象都要维护。这太糟糕了,那么这就引出了我们下一种代理模式,动态代理

动态代理

动态代理不需要生成接口,JDK也提供了API支持,一般都是用jdk中的API来实现的。先看看代码我在代码中添加了很多注释,方便理解。总的来说就是利用反射动态生成代理类。

/**
 * 创建动态代理对象
 * 动态代理不需要实现接口,但是需要指定接口类型
 */
public class ProxyFactory{

    //维护一个目标对象
    private Object target;
    public ProxyFactory(Object target){
        this.target=target;
    }

   //给目标对象生成代理对象
    public Object getProxyInstance(){
    //传入类加载器,接口类,和一个InvocationHandler,然后就会利用反射自动给你生成好代理类返回给你
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                /*proxy就是生成好的动态代理子类,熟悉反射的同学应该能看懂。method为我们所要调用真实子类中的method,Object为该方法接收的参数。*/
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //执行目标对象方法
                        Object returnValue = method.invoke(target, args);

                        return returnValue;
                    }
                }
        );
    }

}

使用

      // 目标对象
        Procurement target = new ShoeProcurement ();
        // 给目标对象,创建代理对象
        ShoeProcurement proxy = (ShoeProcurementProxy ) new ProxyFactory(target).getProxyInstance();
        // 执行方法
        proxy.purchase();

如果需要增加业务,只需增加相应的商品子类,比如PackageProcurement,然后加入动态代理对象即可。so easy。

Cglib代理

上面的代理都需要实现相应的接口,可是有时候我们想代理一个别人写的类,而别人的类并没有实现接口,那咋办呢?这个时候就有Cglib代理了,Cglib是一个动态代码生成包,可以在运行时扩展java类,实现java接口.。运用AOP切面思想,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑,使用的时候需要导入jar包,其他一些问题,这里不详细解释,需要仔细研究的可以看这里。这里我们用一个没有实现接口的ShoeProcurement 来举例

/**
 * 目标对象,没有实现任何接口
 */
public class ShoeProcurement {

    public void purchase() {
        System.out.println("购买物品!");
    }
}
**
 * Cglib子类代理工厂,对ShoeProcurement 在内存中动态构建一个子类对象
 */
public class ProxyFactory implements MethodInterceptor{
    //维护目标对象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    //给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();

    }
//这部分就类似于动态代理了
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        //执行目标对象的方法
        Object returnValue = method.invoke(target, args);
        return returnValue;
    }
}

测试

        //目标对象
        ShoeProcurement target = new ShoeProcurement ();

        //代理对象
        ShoeProcurement proxy = (ShoeProcurement )new ProxyFactory(target).getProxyInstance();

        //执行代理对象的购买方法
        proxy.purchase();

猜你喜欢

转载自blog.csdn.net/HJsir/article/details/80389383