代理模式

代理模式

_

百度简介

代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
著名的代理模式例子为引用计数(英语:reference counting)指针对象。
当一个复杂对象的多份副本须存在时,代理模式可以结合享元模式以减少存储器用量。典型作法是创建一个复杂对象及多个代理者,每个代理者会引用到原本的复杂对象。而作用在代理者的运算会转送到原本对象。一旦所有的代理者都不存在时,复杂对象会被移除。

白话一下:前辈们写了代码,我们要增加功能,但是一改整个项目就莫名其妙崩了,为了不背锅,就要想一个两全其美的办法,在不动原代码的情况下,把功能给增加了。于是就有了代理。

组成

  • 抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
  • 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
  • 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用

案列

房子

public interface House {
    //房屋出租
    public void rent();
}

房东

public class Landlord implements House{

    //房东能出租租房
    @Override
    public void rent() {
        System.out.println("房东租房");
    }
}

中介

public class Mediation implements House{

    //真正要出租房屋的是房东
    private Landlord landlord;

    public Mediation(Landlord landlord) {
        this.landlord = landlord;
    }

    //中介也能出租房屋
    @Override
    public void rent() {
	//中介帮房东租房
        landlord.rent();
        //中介在帮房东出租房屋的同事执行自己的任务
        task();
    }

    //中介有自己的任务
    public void task(){
        System.out.println("中介带看");
        System.out.println("收中介费");
    }
}

test

    @Test
    public void testProxy(){
        Landlord landlord = new Landlord();
        Mediation mediation = new Mediation(landlord);
        mediation.rent();
    }

静态代理结果.png

动态代理

jdk实现了动态代理

java动态代理机制中有一个重要的类和接口:

  • java.lang.reflect.Proxy
  • Interface InvocationHandler

InvocationHandler

每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用

 public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
  • proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0
  • method:我们所要调用某个对象真实的方法的Method对象
  • args:指代代理对象方法传递的参数

Proxy

Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法

//返回指定接口的代理实例,该接口将方法调用分派给指定的调用处理程序。 
static Object newProxyInstance​(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

使用动态代理实现租房

public class ProxyInvocationHandler implements InvocationHandler {

    //代理类中的真实对象
    private Object object;

    //构造函数,给我们的真实对象赋值
    public ProxyInvocationHandler(Object object) {
        this.object = object;
    }

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

        //在真实的对象执行之前我们可以添加自己的操作
        System.out.println("中介");
        Object invoke = method.invoke(object, args);
        //在真实的对象执行之后我们可以添加自己的操作
        System.out.println("带看");
        System.out.println("收中介费");
        return invoke;
    }

    public Object getProxy(){
        //通过Proxy类的newProxyInstance方法创建代理对象
        //第一个参数:使用本身对象的classloader对象来加载我们的代理对象
        //第二个参数:object.getClass().getInterfaces(),这里为代理类提供的接口是真实对象实现的接口,这样代理对象就能像真实对象一样调用接口中的所有方法
        //第三个参数:代理类本身对象
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
    }
}

Test

    @Test
    public void testInvocationHandler(){
        House house = new Landlord();
        House proxy  = (House) new ProxyInvocationHandler(house).getProxy();
        proxy.rent();
    }

Proxy.png

nginx配置 2021-03-22
Emoji 2021-03-27

评论区