• 代理模式


    一、代理模式的作用:将主要业务和次要业务进行松耦合组装
    何时使用:想在访问一个类时做一些控制
     
    代理模式的关键点是:代理对象与目标对象.代理对象是对目标对象的扩展,并会调用目标对象
     
    代理(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();
            
        }
    
    }

    输出结果:

  • 相关阅读:
    洛谷P3128 [USACO15DEC]Max Flow P 题解 树上差分(点差分)
    数列分块解决区间更新+区间最值问题
    ThinkPad P1 Gen3 4K 显示器出现间歇闪黑屏情况解决
    Qt自定义弹出式菜单(Qt自定义弹窗)
    软件产品易用性评价评估标准
    vue用echarts实现中国地图和世界地图
    知了业务逻辑梳理
    string.gfind string.gmatch
    无法定位程序输入点在 XXXX上...
    [Lua]c解析lua 嵌套table
  • 原文地址:https://www.cnblogs.com/currystar/p/10877211.html
Copyright © 2020-2023  润新知