麵包店裡的程式設計狂想
小黑最近手頭有點緊,於是想著去麵包店裡兼職賺點外快。剛剛到麵包店裡上班就看到麵包師傅在做蛋糕和麵包,但是都是手工一個個在做,半個小時才能做出一個蛋糕。程式設計師出身的小黑就不由自主地思考起來,要是能開發出一臺機器,它能自動做蛋糕,那該多好啊。10分鐘就能做出一個蛋糕,10分鐘就能做好一批麵包,這樣效率又高,又可以減掉人力成本。我們用 Java 語言描述一下這個場景:
小黑把這個想法告訴了店長,店長說:不錯,小夥子很有想法。我會嘗試著去做一做,要是做出來了肯定能大大提高生產效率!不知道過了多久,小黑發現店裡竟然真的用機器來做蛋糕和麵包了。
但生活中的場景往往是複雜多變的。就在小黑驚訝的時候,店裡來了一個顧客,他想要一個水果蛋糕,但他特別喜歡杏仁,希望在水果蛋糕上加上一層杏仁。這時候我們應該怎麼做呢?
最簡單的辦法是直接修改水果蛋糕機的程式,做一臺能做杏仁水果蛋糕的蛋糕機。這種方式對應的程式碼修改也很簡單,直接在原來的程式碼上進行修改,生成一臺專門做杏仁水果蛋糕的機器就好了,修改後的 FruitCakeMachien 類應該是這樣子:
雖然上面這種方式實現了我們的業務需求。但是仔細想一想,在現實生活中如果我們遇到這樣的一個需求,我們不可能因為一個顧客的特殊需求就去修改一臺蛋糕機的硬體程式,這樣成本太高!而且從程式碼實現角度上來說,這種方式從程式碼上不是很優雅,修改了原來的程式碼。根據「對修改封閉、對擴充套件開放」的思想,我們在嘗試滿足新的業務需求的時候應該儘量少修改原來的程式碼,而是在原來的程式碼上進行擴充。
那我們究竟應該怎麼做更加合適一些呢?我們肯定是直接用水果蛋糕機做一個蛋糕,然後再人工撒上一層杏仁啦。我們需要做的,其實就是設計一個杏仁代理類(ApricotCakeProxy),這個代理類就完成撒杏仁這個動作,之後讓蛋糕店直接呼叫即可代理類去實現即可。
這其實就對應了即使模式中的代理模式,雖然呼叫的是 ApricotCakeProxy 類的方法,但實際上真正做蛋糕的是 FruitCakeMachine 類。ApricotCakeProxy 類只是在 FruitCakeMachine 做出蛋糕後,撒上一層杏仁而已。而且通過代理,我們不僅可以給水果蛋糕撒上一層杏仁,還可以給巧克力蛋糕、五仁蛋糕等撒上一層杏仁。只要它是蛋糕(實現了 CakeMachine 介面),那麼我們就可以給這個蛋糕撒上杏仁。
通過代理實現這樣的業務場景,這樣我們就不需要在原來的類上進行修改,從而使得程式碼更加優雅,擴充性更強。如果下次客人喜歡葡萄乾水果蛋糕了了,那可以再寫一個 CurrantCakeProxy 類來撒上一層葡萄乾,原來的程式碼也不會被修改。上面說的這種業務場景就是代理模式的實際應用,準確地說這種是靜態代理。
業務場景的複雜度往往千變萬化,如果這個特別喜歡杏仁的客人,他也想在麵包上撒一層杏仁,那我們怎麼辦?我們能夠使用之前寫的 ApricotCakeProxy 代理類麼?不行,因為 ApricotCakeProxy 裡規定了只能為蛋糕(實現了 CakeMachine 介面)的實體做代理。這種情況下,我們只能再寫一個可以為所有面包加杏仁的代理類:ApricotBreadProxy。
我們可以看到我們也成功地做出了客人想要的杏仁紅豆麵包、杏仁葡萄乾麵包。對於客人來說,他肯定希望我們所有的產品都有一層杏仁,這樣客人最喜歡了。為了滿足客人的需求,那如果我們的產品有 100 種(餅乾、酸奶等),我們是不是得寫 100 個代理類呢?
有沒有一種方式可以讓我們只寫一次實現(撒杏仁的實現),但是任何型別的產品(蛋糕、麵包、餅乾、酸奶等)都可以使用呢?其實在 Java 中早已經有了針對這種情況而設計的一個介面,專門用來解決類似的問題,它就是動態代理 —— InvocationHandler。
接下來我們針對這個業務場景做一個程式碼的抽象實現。首先我們分析一下可以知道這種場景的共同點是希望在所有產品上都做「撒一層杏仁」的動作,所以我們就做一個杏仁動態代理(ApricotHandler)。
撒杏仁的代理寫完之後,我們直接讓蛋糕店開工:
public class CakeShop {
public static void main(String[] args) {
//動態代理(可以同時給蛋糕、麵包等加杏仁)
//給蛋糕加上杏仁
FruitCakeMachine fruitCakeMachine = new FruitCakeMachine();
ApricotHandler apricotHandler = new ApricotHandler(fruitCakeMachine);
CakeMachine cakeMachine = (CakeMachine) Proxy.newProxyInstance(fruitCakeMachine.getClass().getClassLoader(),
fruitCakeMachine.getClass().getInterfaces(),
apricotHandler);
cakeMachine.makeCake();
//給麵包加上杏仁
RedBeanBreadMachine redBeanBreadMachine = new RedBeanBreadMachine();
apricotHandler = new ApricotHandler(redBeanBreadMachine);
BreadMachine breadMachine = (BreadMachine) Proxy.newProxyInstance(redBeanBreadMachine.getClass().getClassLoader(),
redBeanBreadMachine.getClass().getInterfaces(),
apricotHandler);
breadMachine.makeBread();
}
}
與靜態代理相比,動態代理具有更加的普適性,能減少更多重複的程式碼。試想這個場景如果使用靜態代理的話,我們需要對每一種型別的蛋糕機都寫一個代理類(ApricotCakeProxy、ApricotBreadProxy、ApricotCookieProxy 等)。但是如果使用動態代理的話,我們只需要寫一個通用的撒杏仁代理類(ApricotHandler)就可以直接完成所有操作了。直接省去了寫 ApricotCakeProxy、ApricotBreadProxy、ApricotCookieProxy 的功夫,極大地提高了效率。
簡單地說,靜態代理只能針對特定一種產品(蛋糕、麵包、餅乾、酸奶)做某種代理動作(撒杏仁),而動態代理則可以對所有型別產品(蛋糕、麵包、餅乾、酸奶等)做某種代理動作(撒杏仁)。
小黑表示一切程式設計思想都可以從現實生活中找到合適的例子,Java 不愧是經典的面嚮物件語言。看到這裡,你們理解靜態代理和動態代理的區別了嗎?歡迎留言告訴我。
歡迎工作一到五年的Java工程師朋友們加入Java架構開發:744677563
本群提供免費的學習指導 架構資料 以及免費的解答
不懂得問題都可以在本群提出來 之後還會有職業生涯規劃以及面試指導
相關文章
- 程式設計師的差距在哪裡?程式設計師的三個級別,你在哪裡?程式設計師
- 麵包第一股:桃李麵包逆勢增長背後的隱憂
- 程式設計師必備的表情包程式設計師
- css麵包屑例項CSS
- 程式設計實戰:如何管理程式碼裡的常量程式設計
- PbootCMS預設麵包屑導航樣式修改及自定義的設定方法boot
- 什麼是程式設計裡的 backoff pattern程式設計
- 大齡程式設計師的前途在哪裡?程式設計師
- 程式設計師在咖啡店程式設計,喝什麼咖啡容易吸引妹紙?程式設計師
- “麵霸” 程式設計師的面試套路,這樣拿到offer的機率提高60%程式設計師面試
- 非科班程式設計師和科班程式設計師的差距到底在哪裡?程式設計師
- 程式設計師的認知體現在哪裡?程式設計師
- 第3章:抽象資料型別(ADT)和麵向物件程式設計(OOP) 3.2設計規約抽象資料型別物件程式設計OOP
- 程式設計師“求包養”攻略揭秘程式設計師
- PbootCMS 7. 麵包屑標籤boot
- Kotlin編寫Processing程式(使用函數語言程式設計思維和麵向介面方式)Kotlin函數程式設計
- 程式設計師的工資到底花到哪裡去了?程式設計師
- 程式設計領域裡有哪些是共通的地方?程式設計
- 如何修改PbootCMS預設麵包屑導航樣式及自定義設定方法boot
- [網路程式設計]mqtt概念&資料包程式設計MQQT
- .NET併發程式設計-函式閉包程式設計函式
- 程式設計師是如何從複雜的程式碼裡找到 bug 的?程式設計師
- 如何把自己包裝成程式設計師大佬?這裡有一份「裝X指南」程式設計師
- 你專屬的程式設計師春節“大禮包”程式設計師
- 使用ASP.NET Blazor Server 寫混合桌面程式的瘋狂想法ASP.NETBlazorServer
- 高階程式設計師到底強在哪裡?程式設計師
- 談談基於機器學習的程式設計到底比傳統程式設計強在哪裡?機器學習程式設計
- python環境包生成_CodingPark程式設計公園Python程式設計
- CSS3麵包屑導航選單CSSS3
- 敏捷史話(九):用做麵包的方式做敏捷——Alistair Cockburn敏捷AI
- 程式設計師IT行業,外行眼裡高收入人群,內行人裡的卷王程式設計師行業
- SAP Spartacus 裡的 icon 設計
- 月入5000和20000的程式設計師,差距到底差在哪裡?程式設計師
- 採訪一個 10 歲的程式設計師,他在 30 萬開發者群裡教程式設計程式設計師
- 一名北漂三年的Java程式設計師題庫總結和麵試經歷Java程式設計師
- 微信小程式搶紅包高併發設計微信小程式
- 《Go 語言程式設計》 讀書筆記 (八) 包Go程式設計筆記
- 好程式設計師web前端教程分享js閉包程式設計師Web前端JS