對客戶端隱藏目標類,創(chuàng)建代理類拓展目標類,并且對于客戶端隱藏功能拓展的細節(jié),使得客戶端可以像使用目標類一樣使用代理類,面向代理(客戶端只與代理類交互)。
專注于為中小企業(yè)提供成都做網(wǎng)站、成都網(wǎng)站制作服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)謝家集免費做網(wǎng)站提供優(yōu)質的服務。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了上千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設實現(xiàn)規(guī)模擴充和轉變。
話不多說,看一個優(yōu)化案例。
目前的功能是下載可以下載文件。
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ù)組
}
}
客戶端調用代碼,如下。
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),這個下載類有一個問題:每次調用都肯定會下載新的文件,即便文件已經(jīng)被下載過。
為了解決這個問題,開發(fā)團隊經(jīng)過商討已經(jīng)有了一個初步的方案??匆幌麓a樣例。
團隊決定使用傳統(tǒng)的修改方式(直接修改BiliBiliDownloader),認為這樣最為的直觀。確實,代碼量少且未來可以預期修改不頻繁時,傳統(tǒng)的修改方案也未嘗不是一個好的選擇。
public class BiliBiliDownloader {
// 定義用來緩存數(shù)據(jù)的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]; // 假裝這是下載后的字節(jié)數(shù)組
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");
// 由于文件已經(jīng)緩存,所以這次下載非??? downloader.download("/root/home/buzuweiqi/java_manual.txt");
// 由于文件還未緩存,所以這次下載比較緩慢
downloader.download("/root/home/buzuweiqi/linux_manual.txt");
}
}
到目前為止好像都沒有啥不妥的地方。直到有一天,客戶提出了新的需求:雖然現(xiàn)在只可以下載bilibili的文件(視頻,音頻,文章等),以后還想要下載youtube的文件。
為了實現(xiàn)這個需求,以及方便以后同類的需求變更,是時候用上代理模式。
代理模式在使用的時候需要頂一個一個頂層接口,并且使得代理類和被代理類都實現(xiàn)這個接口。
代理類中需要持有非代理類的一個對象。并且在調用代理類的功能前后可以根據(jù)業(yè)務需要拓展新的功能。
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<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]; // 假裝是下載文件的字節(jié)數(shù)組
}
}
public class ProxyYoutubeDownloader 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("正在下載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");
}
}
客戶端不再依賴目標類,而是轉而依賴代理類。
代理模式使得增加相似需求時可以只增加一對實現(xiàn)類(目標類,代理類),而不用修改原本的類,符合開閉原則。
實際上通常我們會使用一個更為簡單的方式控制代理對象的創(chuàng)建:反射。
高層接口,實現(xiàn)的目標類、代理類依舊不變。
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<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]; // 假裝是下載文件的字節(jié)數(shù)組
}
}
public class ProxyYoutubeDownloader 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("正在下載Youtube文件:%s%n", filePath);
return map.get(filePath);
}
byte[] res = downloader.download(filePath);
map.put(filePath, res);
return res;
}
}
在客戶端調用時,引入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反射機制,應對每次的需求變更,甚至都不需要修改客戶端代碼,只需要修改案例中的config.prop
即可。減少了不必要的代碼修改,提高了系統(tǒng)的可維護性。
代理類與目標類的使用方式一致,這極大的降低了客戶端調用的學習成本,易用性高。
面向接口,無需在意實現(xiàn)的細節(jié)。
除此之外還有很多應用場景,代理模式是設計模式中使用非常廣泛的一種。
網(wǎng)頁題目:設計模式---代理模式
網(wǎng)站鏈接:http://chinadenli.net/article22/dsoidcc.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營銷推廣、響應式網(wǎng)站、定制網(wǎng)站、靜態(tài)網(wǎng)站、微信公眾號、用戶體驗
聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)