常见设计模式——代理模式

Intent

控制对其它对象的访问。

Class Diagram

抽象角色:声明真实对象和代理对象的共同接口,这样在任何使用真实对象的地方都可以使用代理对象。

代理角色:代理对象内部含有真实对象的引用,从而可以在任何时候操作真实对象。代理对象和真实对象具有相同的接口,这样就可以在任何时候替代真实对象。代理对象通常在执行真实对象的操作前后,附加某些其他的操作,相当于对真实对象进行封装。

真实角色:即为代理对象所代理的真实对象,是我们最终要引用的对象。

Implementation

// 抽象角色
interface Subject{
    public void doSomething();
}

// 目标角色
class RealSubject implements Subject{
    public void doSomething() {
        System.out.println("call doSomething()");
    }
}

// 代理角色
class SubjectProxy implements Subject{
    // 代理持有目标对象的引用
    Subject subimpl = new RealSubject();

    public void doSomething() {
        System.out.println("before"); //调用目标对象之前可以做相关操作
        subimpl.doSomething();
        System.out.println("after");//调用目标对象之后可以做相关操作
    }
}

public class Test {
    public static void main(String[] args) throws Exception {
        Subject sub = new SubjectProxy();
        sub.doSomething();
    }
}

存在的问题:

1. 如果 RealSubject 将来需要实现一个新的接口,就需要在代理类里再写该接口的实现方法,导致代理类的代码变得臃肿

2. 当需要改变抽象角色接口时,无疑真实角色和代理角色也需要改变。

JDK动态代理

package com.eastern.msap.test;

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

interface Subject {
    public void doSomething();
}

class RealSubject implements Subject {
    public void doSomething() {
        System.out.println("call doSomething()");
    }
}

class ProxyHandler implements InvocationHandler {

    private Object target;

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

    public Object getProxyInstance() {

        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),// 绑定该类实现的所有接口,取得代理类
                this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result;
        System.out.println("在调用具体函数方法前,执行功能处理");
        result = method.invoke(target, args);
        System.out.println("在调用具体函数方法后,执行功能处理");
        return result;
    }
}

public class Test {
    public static void main(String args[]) {
        ProxyHandler proxyHandler = new ProxyHandler(new RealSubject());
        Subject sub = (Subject) proxyHandler.getProxyInstance();
        sub.doSomething();
    }
}
在调用具体函数方法前,执行功能处理
call doSomething()
在调用具体函数方法后,执行功能处理

对于问题一,因为JDK动态代理是根据目标对象实现的所有接口生成代理类对象的,所以如果目标对象需要实现新接口时,生成代理类的代码不用做更改。

对于问题二,当接口改变的时候,虽然【被代理类】需要改变,生成代理类的代码也不用更改。

这个调用虽然足够灵活,可以动态生成一个具体的代理类,而不用自己显式的创建一个实现具体接口的代理类。

原文地址:https://www.cnblogs.com/codestarer/p/13635529.html