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文件

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

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

原文地址:https://www.cnblogs.com/qyf2199/p/14613286.html