代理模式

原来的对象丢进代理类中,代理类会添加自己的属性和操作,如控制对象的访问,或者将原来的方法进行完善,如添加日志。这也是Spring aop的实现原理。

代理模式偏向于完善某个特定的方法,所以经常是要和被代理的真实角色实现同一个方法。对象的实例常常是代理类中进行创建。

1. 装饰者模式和代理模式的区别

装饰者模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话 说,用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰者模式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。

2. 静态代理

角色分析:

  1. 抽象角色:一般会使用接口或者抽象类实现。
  2. 真实角色:被代理角色。
  3. 代理角色:代理真实的角色,代理真实角色后会做附属操作。
  4. 客户:访问代理对象的角色。
public class StaticProxy {
    public static void main(String[] args) {
        You you = new You();    // 你要结婚
        WeddingCompany weddingCompany = new WeddingCompany(you);
        weddingCompany.happyMarry();
    }
}

interface Marry {
    void happyMarry();
}

// 真实角色,你去结婚
class You implements Marry {
    @Override
    public void happyMarry() {
        System.out.println("要结婚了,超开心");
    }
}

// 代理角色,帮助你结婚
class WeddingCompany implements Marry {

    // 代理谁-> 真实目标角色
    private Marry target;

    public WeddingCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void happyMarry() {
        before();
        this.target.happyMarry(); // 这就是真实对象
        after();
    }

    private void after() {
        System.out.println("结婚后,收尾款");
    }

    private void before() {
        System.out.println("结婚前,布置现场");
    }
}

总结:

  1. 真实对象和代理对象都要实现同一个接口。
  2. 代理对象要代理真实角色。

好处:

  1. 代理对象可以做很多公共的业务,实现业务的分工。
  2. 真实对象专注做自己的业务。
  3. 公共业务发生扩展的时候,方便集中管理。

缺点:

静态代理中一个真实角色就会产生一个代理角色,开发效率低。

实现Runnable接口创建线程作对比:

  1. Marry接口——>Runnable接口
  2. 实现Marry接口的You类——>实现Runnable接口的自己编写的类
  3. 实现Marry接口的WeddingCompany类——>实现Runnable接口的Thread类

Thead类实际上就是一个代理类。

3. 动态代理

动态代理就是通过反射完成代理的实现。

  1. 动态代理和静态代理的角色相同。
  2. 动态代理类是动态生成的。
  3. 动态代理的分类:基于接口的动态代理,基于类的动态代理。
    • 基于接口--JDK动态代理
    • 基于类:cglib
    • Java字节码实现:javasist(JBoss)
  4. 动态代理需要用到的类:Proxy(代理)、InovationHandler(调用处理程序)。

将上面的静态代理转成动态代理模式

public class DynamicProxy {
    public static void main(String[] args) {
        You you = new You();    // 你要结婚
        WeddingCompany weddingCompany = new WeddingCompany();
        weddingCompany.setTarget(you);
        Marry proxy = (Marry) weddingCompany.getProxy();
        proxy.happyMarry();
    }
}

interface Marry {
    void happyMarry();
}

// 真实角色,你去结婚
class You implements Marry {
    @Override
    public void happyMarry() {
        System.out.println("要结婚了,超开心");
    }
}

class WeddingCompany implements InvocationHandler {
    private Marry target;

    public void setTarget(Marry target) {
        this.target = target;
    }

    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object object = method.invoke(target, args);
        after();
        return object;
    }

    private void after() {
        System.out.println("结婚后,收尾款");
    }

    private void before() {
        System.out.println("结婚前,布置现场");
    }
}

万能动态代理类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxy implements InvocationHandler {
    Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = method.invoke(proxy, args);

        return object;
    }
}

动态代理类中的invoke方法,可以做的事情比静态代理多很多(反射)。而且代码可以做到很简洁。

动态代理的好处:

  1. 静态代理类的好处都有。
  2. 一个动态代理类代理的是一个接口或者一个父类,一般就是对应的一类业务。
  3. 一个动态代理类可以代理多个类,只要是实现了同一个接口即可。
Copyright © rootwhois.cn 2021-2022 all right reserved,powered by GitbookFile Modify: 2023-03-05 10:55:52

results matching ""

    No results matching ""