设为首页 加入收藏

TOP

设计模式---代理模式(一)
2023-07-25 21:31:15 】 浏览:52
Tags:计模式 ---

简述

对客户端隐藏目标类,创建代理类拓展目标类,并且对于客户端隐藏功能拓展的细节,使得客户端可以像使用目标类一样使用代理类,面向代理(客户端只与代理类交互)。

话不多说,看一个优化案例。

优化案例

最初版v0

目前的功能是下载可以下载文件。

public class BiliBiliDownloader {
    public byte[] download(String filePath) throws InterruptedException {
        System.out.printf("正在下载BiliBili文件:%s%n", filePath);
        // 模拟文件下载,睡个10秒
        Thread.sleep(10000);
        return new byte[1024]; // 假装是下载文件的字节数组
    }
}

客户端调用代码,如下。

public class Client {
    public static void main(String[] args) throws InterruptedException {
        BiliBiliDownloader bilidownloader = new BiliBiliDownloader();
        bilidownloader.download("/root/buzuweiqi/java_manual.txt");
    }
}

下载工具类对客户端完全暴露,客户端可以直接使用下载类实现下载,这实际上是无可厚非的。
经过研究发现,这个下载类有一个问题:每次调用都肯定会下载新的文件,即便文件已经被下载过。

为了解决这个问题,开发团队经过商讨已经有了一个初步的方案。看一下代码样例。

修改版v1

团队决定使用传统的修改方式(直接修改BiliBiliDownloader),认为这样最为的直观。确实,代码量少且未来可以预期修改不频繁时,传统的修改方案也未尝不是一个好的选择。

public class BiliBiliDownloader {
    // 定义用来缓存数据的map对象
    private static Map<String, byte[]> map = new HashMap<>();
    public byte[] download(String filePath) throws InterruptedException {
        System.out.printf("正在下载BiliBili文件:%s%n", filePath);
        if (map.containsKey(filePath)) {
            return map.get(filePath);
        }
        // 模拟文件下载,睡个10秒
        Thread.sleep(10000);
        byte[] res = new byte[1024]; // 假装这是下载后的字节数组
        map.put(filePath, res); // 加入缓存
        return res;
    }
}

客户端调用代码,还是和原来一样。

public class Client {
    public static void main(String[] args) throws IOException, InterruptedException {
        BiliBiliDownloader downloader = new BiliBiliDownloader();
        downloader.download("/root/home/buzuweiqi/java_manual.txt");
        // 由于文件已经缓存,所以这次下载非常快
        downloader.download("/root/home/buzuweiqi/java_manual.txt");
        // 由于文件还未缓存,所以这次下载比较缓慢
        downloader.download("/root/home/buzuweiqi/linux_manual.txt");
    }
}

到目前为止好像都没有啥不妥的地方。直到有一天,客户提出了新的需求:虽然现在只可以下载bilibili的文件(视频,音频,文章等),以后还想要下载youtube的文件。

为了实现这个需求,以及方便以后同类的需求变更,是时候用上代理模式。

修改版v2

代理模式在使用的时候需要顶一个一个顶层接口,并且使得代理类和被代理类都实现这个接口。
代理类中需要持有非代理类的一个对象。并且在调用代理类的功能前后可以根据业务需要拓展新的功能。

public interface Downloader {
    byte[] download(String filePath) throws InterruptedException;
}

public class BiliBiliDownloader implements Downloader {
    public byte[] download(String filePath) throws InterruptedException {
        System.out.printf("正在下载BiliBili文件:%s%n", filePath);
        // 模拟文件下载,睡个10秒
        Thread.sleep(10000);
        return new byte[1024]; // 假装是下载文件的字节数组
    }
}

public class ProxyBiliBiliDownloader implements Downloader {
    private static Map<String, byte[]> map = new HashMap<>();
    private BiliBiliDownloader downloader = new BiliBiliDownloader();
    public byte[] download(String filePath) throws InterruptedException {
        if (map.containsKey(filePath)) {
            System.out.printf("正在下载BiliBili文件:%s%n", filePath);
            return map.get(filePath);
        }
        byte[] res = downloader.download(filePath);
        map.put(filePath, res);
        return res;
    }
}

public class YoutubeDownloader implements Downloader {
    public byte[] download(String filePath) throws InterruptedException {
        System.out.printf("正在下载Youtube文件:%s%n", filePath);
        // 模拟文件下载,睡个10秒
        Thread.sleep(10000);
        return new byte[1024]; // 假装是下载文件的字节数组
    }
}

public class ProxyYoutubeDownloader implements Downloader {
    private static Map<String, byte[]> map = new HashMap<>
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇手写模拟spring底层原理 下一篇log4j 1 升级方案

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目