2009-04-15 65 views
5

我認爲,以下是不能用Java完成的。但我很樂意學習如何實現類似的東西。事實之後實現接口

假設我們有一個C類,它已經在編譯代碼中使用了。 (我們既不能更改該代碼也不能更改C的原始定義)。

假設進一步有一些有趣的代碼可以被重用,如果只有C實現接口I的話。事實上,或多或少地推導D,這只是C +接口方法的實現。

然而,似乎沒有辦法,一旦我有一個C,說:我想你是一個d,就是實現一

(邊此言一C:我覺得演員(D)c,其中c的運行時類型爲C,如果D是C並且與C唯一的區別是添加了方法,那麼應該允許這應該是安全的,如果不是這樣,它應該是安全的)。災害?我知道工廠的設計模式,但這似乎並不是一種解決方案,因爲一旦我們在所有以前是C的地方設法創建D,其他人就會發現另一個接口J有用並且衍生出E擴展C實現了J.但是E和D是不兼容的,因爲它們都向C添加了一組不同的方法。所以雖然我們總是可以傳遞一個E來預期C,但是我們不能在期望D時傳遞E。相反,現在,我們需要一個新的類F擴展C實現I,J。)

回答

7

如果所有你需要與兼容的接口,那麼沒問題看看dynamic proxy classes,它基本上是如何在運行時在java中實現接口的。

如果你需要與類的運行時兼容性,我建議你看看cglib或javaassist開源庫。

10

難道你不能使用一個委託類,即一個新類包裝一個「C類」的實例,但也實現「界面我」?

public class D implements I { 

    private C c; 

    public D (C _c) { 
     this.c = _c; 
    } 

    public void method_from_class_C() { 
     c.method_from_class_C(); 
    } 
    // repeat ad-nauseum for all of class C's public methods 
    ... 

    public void method_from_interface_I() { 
     // does stuff 
    } 
    // and do the same for all of interface I's methods too 
} 

,然後,如果你需要調用一個函數,一般需I類型的參數,只是這樣做:

result = some_function(new D(c)); 
+0

爲什麼不簡單地「D類擴展C實現I」? – dfa 2009-04-15 15:04:54

+0

,因爲它要麼用'new D(...)'而不是'new C(...)'來構建,這可能是不可能的。儘管D延伸C,也不可能做「D d =(D)C」。儘管如此,從D到C的向下應該是可能的。 – Alnitak 2009-04-15 15:14:56

+0

我曾試圖解釋過。 我從不受我控制的代碼獲取C,並想將它們(不是新的/不同的對象)傳遞給與接口一起工作的代碼。 – Ingo 2009-04-15 15:17:00

3

如果你(能)管理加載您C類,那麼你可以嘗試做一些類加載時間有心計字節碼儀器,使類實現接口的ClassLoader

當然,在構建時也可以做同樣的事情。它可能更容易這樣(因爲你不需要訪問ClassLoader)。

1

我相信你想要的是可以使用java.lang.reflect.Proxy;事實上,我爲當前的項目做了類似的事情。然而,這是相當多的工作,並且由此產生的「混合對象」會暴露出奇怪的行爲(因爲它們上的方法調用會被路由到不同的具體對象,當這些方法試圖互相調用時會出現問題)。

2

(邊注:我覺得演員(d)C, 其中c的運行時類型是C,應該 允許如果d是一個C和唯一 差下加入方法 這應該。要安全,不是嗎?)

根本不是。如果你能做出這樣投,那麼你可以編譯試圖調用該對象的「添加方法」之一,它會在運行時失敗,因爲該方法不C.

存在,我認爲你是想象碼演員會檢測C中「缺失」的方法並自動將它們委派給D。我懷疑這是否可行,儘管我無法說出語言設計的含義。

在我看來,解決你的問題是:

定義d類,它擴展了C和實現我
定義構造函數d(C C)基本上克隆給定的C對象的狀態改變成一個新的D對象。
的d對象可以傳遞到您現有的代碼,因爲它是一個C,它可以傳遞到想要的我,因爲它是我

0

我認爲你不能這樣做,因爲Java是代碼嚴格打字。我相信它可以用像Ruby和Python這樣的語言來完成,並使用mixin。

對於Java而言,它看起來像適配器設計模式的一個很好的用法(它早已被提議作爲「包裝器」對象)。