结构型(一) - 代理模式

一、概念

代理模式(Proxy Pattern):它在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加新功能。

使用场景:代理模式最常用的一个应用场景就是,在业务系统中开发一些非功能性需求,比如:监控、统计、鉴权、限流、事务、幂等、日志。我们将这些附加功能与业务功能解耦,放到代理类中统一处理,让程序员只需要关注业务方面的开发。

二、实现

  • 静态代理

借鉴下面参考文章VPN的例子,实现了静态代理:

1、定义网站接口

java 复制代码
public interface Website {
    void processRequest();
    void saveHistory();
}

2、实现网站Baidu实例

java 复制代码
public class Baidu implements Website{
    @Override
    public void processRequest() {
        System.out.println("正在访问Baidu");
    }

    @Override
    public void saveHistory() {
        System.out.println("保存访问Baidu记录");
    }
}

3、访问baidu网站

java 复制代码
public class Client {
    public static void main(String[] args) {
        Baidu baidu = new Baidu();
        baidu.processRequest();
        baidu.saveHistory();
    }
}

4、访问结果:

5、实现网站Youtube实例

java 复制代码
public class Youtube implements Website{
    @Override
    public void processRequest() {
        System.out.println("正在访问Youtube");
    }

    @Override
    public void saveHistory() {
        System.out.println("保存访问Youtube记录");
    }
}

6、如果我们要访问国外的网站Youtube,Facebook等,直接访问是不行的,我们就需要加一个vpn,登录vpn后可正常访问。所以我们需要在访问Youtube这些网站前加上vpn登录校验功能,如果未登录先登录vpn在去访问。但是如果每个网站的每个方法前挨个加判断太麻烦了,所以我们写一个代理类,统一给这些国外的网站加上登录校验功能。

java 复制代码
public class VPN implements Website {
    private Website proxiedWebsite;
    public VPN (Website wb){
        this.proxiedWebsite = wb;
    }

    @Override
    public void processRequest() {
        loginVpn();
        proxiedWebsite.processRequest();
    }

    @Override
    public void saveHistory() {
        loginVpn();
        proxiedWebsite.saveHistory();
    }

    private void loginVpn() {
        System.out.println("校验vpn登录状态,已登录");
    }
}

总结:个人理解,vpn这里相当于一个网站代理,我们把要访问的网站给代理类,代理类会处理vpn登录等判断并帮我们访问我们需要的网站。vpn登录功能相对于之前的网站访问及网站历史记录等网站业务功能是相对独立的,所以直接加在原来代码中不合理,因此该功能抽出来用代理类去处理。

7、访问Youtube :

java 复制代码
public class Client {
    public static void main(String[] args) {
        //Baidu baidu = new Baidu();
        //baidu.processRequest();
        
        //直接访问
        //Youtube youtube = new Youtube();
        //youtube.processRequest();
        //youtube.saveHistory();

        //代理访问
        Website youtube = new VPN(new Youtube());
        youtube.processRequest();
        youtube.saveHistory();
    }
}

8、运行结果:

总结:从上面的例子可以看出,VPN需要实现Website接口,代理类需要把实现类的方法都实现一遍。后面增加登录校验功能,就需要在每个实现方法中都加一遍。

  • 动态代理

动态代理就是我们不事先为每个原始类编写代理类,而是在运行的时候,动态地创建原始类对应的代理类,然后在系统中用代理类替换掉原始类。

代码实现:

1、动态代理实现,先实现接口InvocationHandler,然后通过Proxy类的newProxyInstance()方法创建这个代理。被代理类方法通过反射调用invoke执行,我们在每次执行前加一个vpn登录校验。

java 复制代码
public class WebsiteHandler implements InvocationHandler {
    private Website proxiedObject;

    public WebsiteHandler(Website wb) {
        this.proxiedObject = wb;
    }

    public Website getProxyInstance() {
        return (Website) Proxy.newProxyInstance(this.getClass().getClassLoader()
                , proxiedObject.getClass().getInterfaces(), this);
    }

   @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        loginVpn();
        return method.invoke(proxiedObject, args);
    }

    private void loginVpn() {
        System.out.println("校验vpn登录状态,已登录");
    }
}

2、代理实现和调用

java 复制代码
public class Client {
    public static void main(String[] args) {
        //Baidu baidu = new Baidu();
        //baidu.processRequest();
        
        Youtube youtube = new Youtube();
        WebsiteHandler websiteHandler = new WebsiteHandler(youtube);
        Website website = websiteHandler.getProxyInstance();
        website.processRequest();
        website.saveHistory();
    }
}

3、运行结果

总结:这里我们没有去写一个代理类,而是交给Proxy去生成,然后在InvocationHandlerinvoke方法去实际执行。这个代理类,是在运行阶段生成的,无需事前写好。从上面例子可以看到,如果加功能的话在反射调用的时候统一加上就行,无需像静态代理一样在每个实现方法中都加一遍。

参考文章:
设计模式之代理模式

相关推荐
wuqingshun3141598 天前
什么是代理模式?一般用在什么场景?
java·mysql·代理模式
我登哥MVP8 天前
走进 Gang of Four 设计模式:代理模式
设计模式·代理模式
折哥的程序人生 · 物流技术专研10 天前
Java 23 种设计模式:从踩坑到精通 | 番外:代理 vs 装饰器 —— Spring AOP 到底用了哪个?
java·代理模式·装饰器模式·java面试·java设计模式·springaop·从踩坑到精通
初学者,亦行者11 天前
算法设计与分析3:贪心法 - 求解最短路径问题(TSP)
算法·代理模式
2501_9160074714 天前
iPad 怎么抓包 从代理模式到暴力抓包的操作方法
android·ios·小程序·uni-app·代理模式·iphone·ipad
越甲八千14 天前
代理模式和适配器模式区别
代理模式·适配器模式
AI人工智能+电脑小能手18 天前
【大白话说Java面试题 第156题】【06_Spring篇】第16题:Spring 用到了哪些设计模式?
java·spring·设计模式·代理模式·工厂模式
许彰午1 个月前
36_Java设计模式之代理模式
java·设计模式·代理模式
devilnumber1 个月前
静态代理 & 动态代理:实战运用 + 场景区别 + 怎么选
java·开发语言·代理模式
devilnumber1 个月前
想真正吃透 + 灵活运用 Java 代理模式
java·开发语言·代理模式