最近2018中文字幕在日韩欧美国产成人片_国产日韩精品一区二区在线_在线观看成年美女黄网色视频_国产精品一区三区五区_国产精彩刺激乱对白_看黄色黄大色黄片免费_人人超碰自拍cao_国产高清av在线_亚洲精品电影av_日韩美女尤物视频网站

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
設(shè)計模式---代理模式

簡述

對客戶端隱藏目標(biāo)類,創(chuàng)建代理類拓展目標(biāo)類,并且對于客戶端隱藏功能拓展的細(xì)節(jié),使得客戶端可以像使用目標(biāo)類一樣使用代理類,面向代理(客戶端只與代理類交互)。

專注于為中小企業(yè)提供成都做網(wǎng)站、成都網(wǎng)站制作服務(wù),電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)謝家集免費做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了上千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴充和轉(zhuǎn)變。

話不多說,看一個優(yōu)化案例。

優(yōu)化案例

最初版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]; // 假裝是下載文件的字節(jié)數(shù)組
    }
}

客戶端調(diào)用代碼,如下。

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

下載工具類對客戶端完全暴露,客戶端可以直接使用下載類實現(xiàn)下載,這實際上是無可厚非的。
經(jīng)過研究發(fā)現(xiàn),這個下載類有一個問題:每次調(diào)用都肯定會下載新的文件,即便文件已經(jīng)被下載過。

為了解決這個問題,開發(fā)團隊經(jīng)過商討已經(jīng)有了一個初步的方案。看一下代碼樣例。

修改版v1

團隊決定使用傳統(tǒng)的修改方式(直接修改BiliBiliDownloader),認(rèn)為這樣最為的直觀。確實,代碼量少且未來可以預(yù)期修改不頻繁時,傳統(tǒng)的修改方案也未嘗不是一個好的選擇。

public class BiliBiliDownloader {
    // 定義用來緩存數(shù)據(jù)的map對象
    private static Map 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]; // 假裝這是下載后的字節(jié)數(shù)組
        map.put(filePath, res); // 加入緩存
        return res;
    }
}

客戶端調(diào)用代碼,還是和原來一樣。

public class Client {
    public static void main(String[] args) throws IOException, InterruptedException {
        BiliBiliDownloader downloader = new BiliBiliDownloader();
        downloader.download("/root/home/buzuweiqi/java_manual.txt");
        // 由于文件已經(jīng)緩存,所以這次下載非???        downloader.download("/root/home/buzuweiqi/java_manual.txt");
        // 由于文件還未緩存,所以這次下載比較緩慢
        downloader.download("/root/home/buzuweiqi/linux_manual.txt");
    }
}

到目前為止好像都沒有啥不妥的地方。直到有一天,客戶提出了新的需求:雖然現(xiàn)在只可以下載bilibili的文件(視頻,音頻,文章等),以后還想要下載youtube的文件。

為了實現(xiàn)這個需求,以及方便以后同類的需求變更,是時候用上代理模式。

修改版v2

代理模式在使用的時候需要頂一個一個頂層接口,并且使得代理類和被代理類都實現(xiàn)這個接口。
代理類中需要持有非代理類的一個對象。并且在調(diào)用代理類的功能前后可以根據(jù)業(yè)務(wù)需要拓展新的功能。

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]; // 假裝是下載文件的字節(jié)數(shù)組
    }
}

public class ProxyBiliBiliDownloader implements Downloader {
    private static Map 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]; // 假裝是下載文件的字節(jié)數(shù)組
    }
}

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

客戶端的使用案例如下。

public class Client {
    public static void main(String[] args) throws IOException, InterruptedException {
        Downloader downloader = new ProxyBiliBiliDownloader();
        downloader.download("/root/home/buzuweiqi/java_manual.txt");
        downloader = new ProxyYoutubeDownloader();
        downloader.download("/root/home/buzuweiqi/linux_manual.txt");
    }
}

客戶端不再依賴目標(biāo)類,而是轉(zhuǎn)而依賴代理類。
代理模式使得增加相似需求時可以只增加一對實現(xiàn)類(目標(biāo)類,代理類),而不用修改原本的類,符合開閉原則。

實際上通常我們會使用一個更為簡單的方式控制代理對象的創(chuàng)建:反射。

修改版v3

高層接口,實現(xiàn)的目標(biāo)類、代理類依舊不變。

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]; // 假裝是下載文件的字節(jié)數(shù)組
    }
}

public class ProxyBiliBiliDownloader implements Downloader {
    private static Map 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]; // 假裝是下載文件的字節(jié)數(shù)組
    }
}

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

在客戶端調(diào)用時,引入Java反射,通過反射創(chuàng)建具體的代理對象。
config.prop文件中定義PROXY_NAME變量并指定需要反射創(chuàng)建的類的完整路徑

public class Client {
    public static void main(String[] args) throws Exception {
        Properties prop = new Properties();
        prop.load(new FileReader("src/resource/props/config.prop"));
        Downloader downloader = (Downloader) Class.forName(prop.getProperty("PROXY_NAME"))
                .getDeclaredConstructor().newInstance();
        downloader.download("/root/home/buzuweiqi/java_manual.txt");
        downloader = new ProxyYoutubeDownloader();
        downloader.download("/root/home/buzuweiqi/linux_manual.txt");
    }
}

通過Java反射機制,應(yīng)對每次的需求變更,甚至都不需要修改客戶端代碼,只需要修改案例中的config.prop即可。減少了不必要的代碼修改,提高了系統(tǒng)的可維護性。

總結(jié)

優(yōu)點

  • 代理類與目標(biāo)類的使用方式一致,這極大的降低了客戶端調(diào)用的學(xué)習(xí)成本,易用性高。

  • 面向接口,無需在意實現(xiàn)的細(xì)節(jié)。

缺點

  • 類的數(shù)量倍增,系統(tǒng)復(fù)雜度增加。

適用場景

  • 當(dāng)需要對于模塊拓展,但又不方便打破客戶端原有的調(diào)用規(guī)則時??蛻舳酥袑ο蟮膭?chuàng)建依舊需要修改,這沒有什么好的辦法。
  • 常用的代理模式使用方案
    • 緩沖代理(案例)
    • 遠程代理
    • 虛擬代理

除此之外還有很多應(yīng)用場景,代理模式是設(shè)計模式中使用非常廣泛的一種。


新聞標(biāo)題:設(shè)計模式---代理模式
當(dāng)前URL:http://fisionsoft.com.cn/article/dsoidcc.html