鸭子在Java中打字? 好吧,不完全是
動態類型的類型,其中對象的方法和屬性確定有效的語義,而不是其從特定類或特定接口的實現繼承
用簡單的話
當我看到一只鳥走路像鴨子,游泳像鴨子,嘎嘎像鴨子一樣時,我稱那只鳥為鴨子
在具有動態類型的語言中,此功能允許創建的功能不檢查傳遞的對象的類型,而是依賴于其中存在的特定方法/屬性,并在找不到這些屬性時拋出運行時異常。 例如,在groovy中,我們可以使用一種方法來打印有關某個實體的信息
def printEntity = {entity ->println 'id: ${entity.id}, name: ${entity.name}' }假設我們有以下課程
class Entity {Long idString name }這樣我們就可以調用我們的函數
printEntity(new Entity(id: 10L, name: 'MyName1')) id: 10, name: MyName1但是同時我們可以將map作為參數傳遞
printEntity(['id':10L, 'name':'MyName2']) id: 10, name: MyName2使用一些元編程魔術,我們甚至可以編寫以下內容
class Ghost {def propertyMissing(String name) {if (name == 'id') {return -1L} else if (name == 'name') {return 'StubName'}} }而且我們仍然可以調用我們的函數
printEntity(new Ghost()) id: -1, name: StubName歡迎來到真實的世界
幸運的是,這個概念不僅可以用于具有動態類型的語言,而且可以用于具有更嚴格類型模型的語言,例如Java。 Wikipedia很好地說明了使用Proxy類在Java中進行鴨子輸入的實現。
好吧,你說,除了讓自己成為最聰明的專家以外,這的實際用途是什么:)讓我展示一些使用鴨子類型技術在Java中解決的現實生活任務。
從一開始,我就擁有一個簡單的報表生成器,該報表生成器查詢產品的數據庫并輸出某些實體的ID和名稱。 但隨后客戶說:“我還想鏈接到我們網站上的實體詳細信息頁面。 美麗的SEO友好鏈接。 你能對我做嗎? “當然”,我說。 深入研究我們的代碼庫后,我發現很酷的函數generateSeoUrl()可以完成這項工作。 該函數采用Entity類型的一個參數,即interface。 因此,我的目的是觀察Entity的實現,并嘗試使用其中之一進行報告生成。 當我發現它們全部都是某些自制的ORM工具的一部分并且他們的構造函數接受查詢DB以獲取有關產品的全部信息后,我感到非常驚訝。
因此,如果我使用的是Entity實現,則必須在報表的每一行中處理一個額外的查詢,這是不可接受的,因為報表由大量的行組成。 因此,我決定嘗試其他方法并實現Entity接口,該方法覆蓋了generateSeoUrl()使用的方法。 我單擊了IDE快捷方式,再次感到驚訝。 實體有大約50(!!!)個方法。 好吧,我已經知道generateSeoUrl()函數僅使用getEntityId()和getName(),但是再說一次,使用具有50個空方法的新類來覆蓋其中的2個做有用的動作對我來說不是一個好主意。
因此,我決定停止嘗試編碼,并開始思考:)擴展某些Entity實現以防止查詢數據庫或復制+粘貼generateSeoUrl()并根據我的需要采用它,但是這些選擇仍然很漂亮。 特別是當我提醒鴨子打字時。 我對自己說,我們有一個采用Entity實例但僅使用此接口的兩種方法的函數,因此要完成我的任務,我需要看起來像Entity并能夠處理getEntityId()和getName()方法的東西。
由于實體ID和名稱已經存在于用于生成報告的數據中,因此我可以在新類中重用它們以對getEntityId()和getName()的數據進行存根。 為了實現鴨子類型,我們需要創建Proxy,該Proxy還實現InvocationHandler接口和靜態方法來檢索Proxy實例。 我班的最終代碼看起來像
public class ReportEntitySupport implements InvocationHandler {public static Entity newInstance(Long entityId, String name) {return (Entity) Proxy.newProxyInstance(Product.class.getClassLoader(),Product.class.getInterfaces(),new ReportEntitySupport(entityId, name));}private final String name;private final Long entityId;private ReportEntitySupport(Long entityId, String name) {this.name = name;this.entityId = entityId;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (method.getName().equals('getName')) {return this.name;} else if (method.getName().equals('getEntityId')) {return this.entityId;}return null;} }那么如何使用呢?
在我的報表生成器類中,同時遍歷ResultSet時,我正在使用以下代碼
Long entityId; String name; .... Entity entity = ReportEntitySupport.newIntance(entityId, name); String seoUrl = generateSeoUrl(entity); ....聚苯乙烯
這篇文章僅說明了一些不常見的Java語言概念可以成功地用于完成現實生活中的任務,從而提高您的編程技能并使代碼更漂亮。
參考: 鴨子在Java中打字? 嗯,這不完全是我們JCG合作伙伴 Evgeny Shepelyuk在jk的博客博客上獲得的。
翻譯自: https://www.javacodegeeks.com/2012/09/duck-typing-in-java-well-not-exactly.html
總結
以上是生活随笔為你收集整理的鸭子在Java中打字? 好吧,不完全是的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 世界的本原是什么 世界的本原指的是什么
- 下一篇: 物料是什么意思网络用语 物料的解释