代理模式

一、代理模式的作用:将主要业务和次要业务进行松耦合组装
何时使用:想在访问一个类时做一些控制
 
代理模式的关键点是:代理对象与目标对象.代理对象是对目标对象的扩展,并会调用目标对象
 
代理(Proxy)是一种设计模式,定义:为其他对象提供一个代理以控制对某个对象的访问,即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
  这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法
 
解决的问题: 防止直接访问目标对象给系统带来的不必要复杂性
 
二、生活案例:
1.饭前便后要洗手
主要业务:吃饭;上厕所;
次要业务:洗手;
 
2、jdk代理模式的实现:
2.1接口角色:定义所有需要被监听的行为
2.2接口实现类:中国人,法国人
2.3通知类:
1)次要业务具体实现
2)通知JVM,当前被拦截的主要业务与次要业务应该如何绑定执行
 
2.4监控对象(代理对象):
1)被监控实例对象
2)需要被监控行为
3)具体通知类实例对象
 
三、代码案例(以饭前便后要洗手为例)
 
1.创建需要被监控行为的接口        
2.创建主要业务实现被监控行为
3.创建监控类(通知类),监控需要执行对象的行为
4.创建代理对象,通过代理对象来对我们不同的目标对象(如person,animal),将大家都需要的次要业务和主要业务进行绑定输出。
这里通过代理对象,可以在person功能(吃饭,上厕所)实现的基础上,增强额外的功能(如洗手),可扩展性强。通过代理模式,不会影响主要业务,额外的功能通过代理模式实现就OK,不会修改别人的代码。
 
代码实现:
 1.创建需要被监控行为的接口        
/*
 *	只有需要被监控的行为才有资格在这里声明 
 **/
public interface BaseService {

	void eat();

	void wc();

}

  

2.创建主要业务实现被监控行为
public class Person implements BaseService{

    //主要业务,代理模式要求开发人员只关心主要业务
    @Override
    public void eat() {
        System.out.println("eating......");
    }

    @Override
    public void wc() {
        System.out.println("wc......");
    }

}
3.创建监控类(通知类),监控需要执行对象的行为
public class Invocation implements InvocationHandler {
    // 具体被监控对象
    private BaseService baseService;

    public Invocation(BaseService baseService) {
        this.baseService = baseService;
    }

    /*
     * 
     * invoke方法:在被监控行为将要执行时,会被JVM拦截 被监控行为和行为实现方会被作为参数输送invoke
     * ****通知JVM,这个被拦截方法是如何与当前次要业务方法绑定实现 invoke方法三个参数
     * 
     * int v= 小明.eat();//JVM拦截 method:eat方法封装为Mehtod类型对象
     * params:eat方法运行时接受所有的实参封装到Object[] proxy:将负责监控小明的代理对象作为invoke方法第一个参数
     * 
     */
    // 通知JVM,当前被拦截的主要业务与次要业务应该如何绑定执行
    @Override
    public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
        // 0.局部变量,接受主要业务方法执行完毕后返回值
        Object value;
        // 1.确认当前被拦截行为
        String methodName = method.getName();
        // 2.根据被拦截行为,决定主要业务和次要业务如何绑定执行
        if ("eat".equals(methodName)) {
            // 饭前先洗手
            wash();
            value = method.invoke(this.baseService, params);
        } else {
            // 便后要洗手
            value = method.invoke(this.baseService, params);
            wash();
        }
        // 3.返回被拦截的方法
        return value;
    }

    // 次要业务具体实现
    private void wash() {
        System.out.println("---洗手---");
    }

}
4.创建代理对象,通过代理对象来对我们不同的目标对象(如person,animal),将大家都需要的次要业务和主要业务进行绑定输出。
这里通过代理对象,可以在person功能(吃饭,上厕所)实现的基础上,增强额外的功能(如洗手),可扩展性强。通过代理模式,不会影响主要业务,额外的功能通过代理模式实现就OK,不会修改别人的代码。
/*
 * 
 *  JDK动态代理模式下,代理对象的数据类型
 *  应该由监控行为来描述 
 *  参数: Class文件,监控类
 */
public class ProxyFactory {

    public static BaseService builder(Class<?> classFile) throws Exception {
        // 1.创建一个被监控实例对象
        BaseService baseService = (BaseService) classFile.newInstance();

        // 2.创建一个通知对象
        InvocationHandler adviser = new Invocation(baseService);

        /*
         * newProxyInstance的三个参数: 
         * loader:被监控对象隶属的类文件在内存中真实地址 
         * interfaces:被监控对象隶属的类文件实现接口
         * h:监控对象发现小明要执行被监控行为,应该有哪一个通知对象进行辅助
         */
        // 3.向JVM申请负责监控baseService对象指定行为的监控对象(代理对象)
        BaseService $proxy = (BaseService) Proxy.newProxyInstance(baseService.getClass().getClassLoader(),
                baseService.getClass().getInterfaces(), adviser);

        return $proxy;

    }
}

5.测试代码

public class TestMain {

    public static void main(String[] args) throws Exception {

        BaseService person = ProxyFactory.builder(Person.class);
        person.eat();
        person.wc();
        
        System.out.println("-----------------------------");
        BaseService animal = ProxyFactory.builder(Animal.class);
        animal.eat();
        animal.wc();
        
    }

}

输出结果:

代理模式