结构型(一) - 代理模式

一、概念

代理模式(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方法去实际执行。这个代理类,是在运行阶段生成的,无需事前写好。从上面例子可以看到,如果加功能的话在反射调用的时候统一加上就行,无需像静态代理一样在每个实现方法中都加一遍。

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

相关推荐
Ch.yang2 天前
【Spring】 Bean 注入 HttpServletRequest 能保证线程安全的原理
java·spring·代理模式
biubiubiu07064 天前
代理模式(JDK,CGLIB动态代理,AOP切面编程)
代理模式
痞老板25 天前
【杂谈】虚拟机与EasyConnect运行巧设:Reqable助力指定应用流量专属化
运维·安全·fiddler·代理模式
西岭千秋雪_6 天前
设计模式の享元&模板&代理模式
java·设计模式·代理模式·享元模式·模板方法模式
越甲八千6 天前
重撸设计模式--代理模式
设计模式·代理模式
抓哇FullStack-Junior6 天前
设计模式——代理模式
java·开发语言·设计模式·代理模式
Adellle9 天前
判题机的开发(代码沙箱、三种模式、工厂模式、策略模式优化、代理模式)
java·后端·代理模式·策略模式
夏旭泽13 天前
设计模式-代理模式
设计模式·代理模式
努力学计算机的小白一枚14 天前
力扣1049.最后一块石头的重量(01背包)之理解篇
算法·leetcode·代理模式
lzz的编码时刻17 天前
深入理解代理模式(Proxy):静态代理、动态代理与AOP
java·设计模式·代理模式