zoukankan      html  css  js  c++  java
  • Design Pattern [6] —— 代理模式 Proxy

    意义:代理类在不改变原有类(也就是被代理类)的情况下,对其功能进行扩展.

    分类:静态代理 & 动态代理

    应用:AOP

    我的Github里有源码,可以clone下来自己跑下:https://github.com/Yang2199/Design-Pattern/tree/master/src


    静态代理模式

    /**
     * Worker接口,有一个方法可以卖票;
     */
    interface Worker {
        // 售票方法;
        void sell();
    }
    
    /**
     * 售票员类,实现了Worker接口,可以进行售票,也就是"被代理类"对象;
     */
    class Seller implements Worker {
        @Override
        public void sell() {
            System.out.println("成功把票卖出去了!");
        }
    }
    
    /**
     * 黄牛类,也实现了Worker接口,也可以售票,称为"代理类"对象;
     */
    class Scalper implements Worker {
    
        // 私有一个被代理类的父类引用,这样做是为了适应所有的被代理类对象,只要实现了接口就好;
        private Worker worker;
    
        // 传入被代理类对象,这里的作用是初始化"代理类"中的"被代理类"对象;
        public Scalper(Worker worker) {
            this.worker = worker;
        }
    
        /**
         * 增强服务和功能;
         */
        @Override
        public void sell() {
            // 代理服务;
            worker.sell();
            // 额外服务;
            noQueue();
        }
    
        // 代理类本身自带功能;
        public void noQueue() {
            System.out.println("黄牛附加功能:不用排队哟!!!");
        }
    }
    
    /**
     * 主函数;
     */
    public class StaticProxyDemo {
    
        public static void main(String[] args){
            // 首先是原始类,也就是被代理类;
            System.out.println("======正常买票======");
            Worker worker = new Seller();
            worker.sell();
            System.out.println("======黄牛买票======");
            // 其次是代理类,传入被代理类对象;
            Worker pw = new Scalper(worker);
            pw.sell();
        }
    }

    结果:

    类图:

    动态代理模式

    与静态代理不同,动态代理不需要提前创建对象,只需要提供一个动态创建器,程序会在运行时候动态生成对应的代理类

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    interface App {
        void webSell();
    }
    class TicketApp implements App {
        @Override
        public void webSell() {
            System.out.println("APP卖票:顾村公园");
        }
    }
    
    
    interface Seller {
        // 售票方法;
        void sell();
    }
    class OridinarySeller implements Seller {
        @Override
        public void sell() {
            System.out.println("窗口卖票:顾村公园");
        }
    }
    
    /**
     * 代理类,也就是代理对象,就类似于上述静态代理中的Scalper类;
     */
    class ProxySubject implements InvocationHandler { // 涉及到动态代理需要实现这个接口InvocationHandler
    
        // 实现了接口的被代理类的对象引用声明;
        private Object object;
    
        public Object getNewInstance(Object object) {
            // 实例化被代理类的对象;
            this.object = object;
            // 返回一个代理类的对象;
            /**
             * 这里的newProxyInstance的三个参数:(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
             *      1.第一个参数是需要传入类的加载器,这里指的是被代理类的类加载器,简单来说就是和被代理类使用相同的类加载器;
             *      2.第二个参数是需要传入类的接口,也就是说,这个类实现了哪些接口,我都要传过来;
             *      3.第三个参数是需要传入的一个InvocationHandler对象,指的是代理类对象,也就是调用这个函数的this对象(ProxySubject对象);
             */
            return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
        }
    
        // 当通过代理类的对象发起对被重写的方法的调用时,都会转换为对以下invoke方法的调用;
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 增强代码(前);
            System.out.println("++AOP前附加功能:节日打折");
    
            // 被代理类的方法;
            Object value = method.invoke(object, args);
    
            // 增强代码(后);
            System.out.println("++AOP后附加功能:节日赠品=>吹泡泡机/风筝");
            return value;
        }
    }
    
    public class DynamicProxyDemo {
        public static void main(String[] args){
            // 1.创建被代理类对象;
            TicketApp ticketApp = new TicketApp();
            // 2.创建一个实现了InvocationHandler接口的类的对象;
            ProxySubject proxySubject = new ProxySubject();
            // 3.父类引用指向子类对象;
            App app = (App)proxySubject.getNewInstance(ticketApp);
            // 4.执行代理类的方法;
            app.webSell();
    
            System.out.println("===========================");
            // 使用前面静态代理的例子,创建一个Seller的被代理类对象;
            OridinarySeller oridinarySeller = new OridinarySeller();
            // 创建一个Worker的子类对象,指向Seller的代理类对象;
            Seller seller = (Seller)proxySubject.getNewInstance(oridinarySeller);
            // 执行其方法;
            seller.sell();
        }
    }

    结果:

    类图:

    总结

      代理模式可以在不改变目标类的情况下对功能进行扩展

      静态代理编译时便生成class文件;动态代理运行时通过反射生成对应的class文件

      静态代理需要实现接口的所有方法,一个代理类能服务的目标类有限;动态代理可以只对某些方法进行处理,一个代理处理器可以服务多个目标类

      对于一些接口比较简单、或者自动生成的通用性代码,可以选择使用静态代理;对于一些庞大的接口,频繁地需要改动接口,你已经觉得改得很烦,可以选择使用动态代理。

  • 相关阅读:
    【jQuery UI 1.8 The User Interface Library for jQuery】.学习笔记.2.更换主题
    【jQuery UI 1.8 The User Interface Library for jQuery】.学习笔记.1.CSS框架和其他功能
    终于要开始做大名鼎鼎的BombLab了!
    初识linux内核漏洞利用
    控制转移指令分类与机器码
    Kali Linux信息收集工具全集
    Kali Linux 弱点分析工具全集
    DockerScan:Docker安全分析&测试工具
    SNORT入侵检测系统
    Woobuntu
  • 原文地址:https://www.cnblogs.com/qyf2199/p/14613286.html
Copyright © 2011-2022 走看看