结构型-代理模式 Link to heading

代理模式和装饰模式很像,初学者很容易搞混,所以这里我们得紧接着来讲解一下。首先请记住,当无法直接访问某个对象或访问某个对象存在困难时,我们就可以通过一个代理对象来间接访问。

比如现在有一个目标类,但是我们现在需要通过代理来使用它:

public abstract class Subject {
    public abstract void test();
}
public class SubjectImpl extends Subject{  //此类无法直接使用,需要我们进行代理

    @Override
    public void test() {
        System.out.println("我是测试方法!");
    }
}

现在我们为其建立一个代理类:

public class Proxy extends Subject{   //为了保证和Subject操作方式一样,保证透明性,也得继承

    Subject target;   //被代理的对象(甚至可以多重代理)

    public Proxy(Subject subject){
        this.target = subject;
    }

    @Override
    public void test() {   //由代理去执行被代理对象的方法,并且我们还可以在前后添油加醋
        System.out.println("代理前绕方法");
        target.test();
        System.out.println("代理后绕方法");
    }
}

对装饰器模式来说,装饰者和被装饰者都实现同一个接口/抽象类。对代理模式来说,代理类和被代理的类都实现同一个接口/抽象类,在结构上确实没有啥区别。

  • 装饰器模式强调的是增强自身,在被装饰之后你能够在被增强的类上使用增强后的功能。

  • 代理模式强调要让别人帮你去做事情,以及添加一些本身与你业务没有太多关系的事情。

装饰模式和代理模式的不同之处在于思想。

当然实现代理模式除了我们上面所说的这种方式之外,我们还可以使用JDK为我们提供的动态代理机制,我们不再需要手动编写继承关系创建代理类,它能够在运行时通过反射机制为我们自动生成代理类:

public interface Subject {  //JDK提供的动态代理只支持接口
    void test();
}


public class SubjectImpl implements Subject{

    @Override
    public void test() {
        System.out.println("我是测试方法!");
    }
}

接着我们需要创建一个动态代理的处理逻辑:

public class TestProxy implements InvocationHandler {    //代理类,需要实现InvocationHandler接口

    private final Object object;   //这里需要保存一下被代理的对象,下面需要用到

    public TestProxy(Object object) {
        this.object = object;
    }

    @Override   //此方法就是调用代理对象的对应方法时会进入,这里我们就需要编写如何进行代理了
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
             //method就是调用的代理对象的哪一个方法,args是实参数组
        System.out.println("代理的对象:"+proxy.getClass());   //proxy就是生成的代理对象了,我们看看是什么类型的
        Object res = method.invoke(object, args);   //在代理中调用被代理对象原本的方法,因为你是代理,还是得执行一下别人的业务,当然也可以不执行,但是这样就失去代理的意义了,注意要用上面的object
        System.out.println("方法调用完成,返回值为:"+res);   //看看返回值是什么
        return res;   //返回返回值
    }
}

测试

public static void main(String[] args) {
    SubjectImpl subject = new SubjectImpl();   //被代理的大冤种
    InvocationHandler handler = new TestProxy(subject);
    Subject proxy = (Subject) Proxy.newProxyInstance(
            subject.getClass().getClassLoader(),    //需要传入被代理的类的类加载器
            subject.getClass().getInterfaces(),    //需要传入被代理的类的接口列表
            handler);    //最后传入我们实现的代理处理逻辑实现类
    proxy.test();    //比如现在我们调用代理类的test方法,那么就会进入到我们上面TestProxy中invoke方法,走我们的代理逻辑
}


// 打印值
代理的对象: class com.sun.proxy.$Proxy0
我是测试方法!
方法调用完成,返回值为: null