2012-05-28 24 views
4

在第三方庫我使用的,有層次的下列位:使用第三方抽象類就好像它是一個接口?

public abstract class Foo 
{ 
    // Class is public in the Java sense and public in the library's API 
} 

public class FooImpl extends Foo 
{ 
    // While this class is public in the Java sense, it is 
    // NOT part of the public API and is not even documented 
    // Library functions that hand back instances of this class 
    // hand them back as type Foo 
} 

庫中的各種方法對Foo類型的東西進行操作。 Foo文檔說,用戶可以擴展Foo作出具體的實現,並且(顯然)該庫提供了一個具體的實現。

我很高興圖書館提供的實現,除了一種方法,其行爲我想改變一點。但是我所提供的層次讓我感到沮喪。

如果Foo是一個接口(這是不是!),我只是這樣做:

public FooWrapper implements Foo 
{ 
    private Foo wrappedImpl; 

    public FooWrapper(Foo toBeWrapped) { 
     wrappedImpl = toBeWrapped; 
    } 

    List<Whatever> methodIWantToTweak() { 
     List<Whatever> list = wrappedImpl.methodIWantToTweak(); 
     do_something_to_list(list); 
     return list; 
    } 

    Something methodThatsOk() { 
     return wrappedImpl.methodThatsOk(); 
    } 

    // similar delegations for remaining methods 
} 

但因爲它是不是的接口,我不能這樣做,或者至少不能做得乾乾淨淨。

我能想到這樣做的唯一的事情是:

1)擴展API,非公共類FooImpl並重寫我想調整的方法。

2)做這樣的事情:

public class FooWrapper extends Foo 
{ 
    private Foo wrappedImpl; 

    public FooWrapper(Foo toBeWrapped) { 
     super(); 
     wrappedImpl = toBeWrapped; 
    } 

    List<Whatever> methodIWantToTweak() { 
     List<Whatever> list = wrappedImpl.methodIWantToTweak(); 
     do_something_to_list(list); 
     return list; 
    } 

    Something methodThatsOk() { 
     return wrappedImpl.methodThatsOk(); 
    } 

    // Override all non-final public, protected, and package-local 
    // methods and delegate them to wrappedImpl 
} 

這兩項辦法聞起來像見鬼了我。第一個問題是它依賴於它不應該知道的類,以及在未來版本的庫中可以更改/消失/重命名的類。第二個問題是FooWrapper的超類片段沒有被實際使用,並且不可能覆蓋Foo的任何最終或私有方法(這會導致問題,因爲在那些情況下無法委託給wrappedImpl)。

我想我必須採用第一種方法,因爲至少它會給出正確的行爲,而第二種可能會以潛在的惡劣,細微的方式破壞,具體取決於Foo的內部細節。

我剛好運氣好嗎?我忽略了什麼其他方法/想法?

+0

爲什麼你不能覆蓋你想調整的方法?你可以提供相同的實現,除非你調用base而不是wrappedImpl。我錯過了什麼嗎? – dasblinkenlight

+0

@dasblinkenlight - 你可能會丟失的是,OP可能無法改變創建Foo實例的代碼,使其創建* his * Foo子類的實例。包裝可以解決這個問題。 –

回答

2

我想不出任何其他方法不會更臭! (反射會起作用,但在這種情況下,它會比您要避免的問題更糟糕。)

我認爲第二種方法是最好的。如果Foo抽象類被設計爲公共類,那麼不應該有有令人討厭的內部細節,可能會讓你感到不安。如果是這樣,他們的設計就錯了。

注意,因爲你正在創建「真正的」富實例的包裝類:

  • 你大概可以忽略大部分是抽象類提供的功能「真正的」富子類使用。

  • 您可以忽略任何由Foo級別屬性表示的狀態。

  • 你可以在API中存儲你不需要在你的應用程序中使用的方法;例如編碼他們扔UnsupportedOperationException

所有這些都有助於降低問題的複雜性。

3

如果您不需要重寫Foo的最終或受保護方法(請參閱下面的方法),我會採用第二種方法:將Foo作爲界面,並在該情況下執行您的操作。優點是您不依賴可以更改的FooImpl

finalprivateFoo方法是沒有問題的,因爲你不能將能夠覆蓋在FooImpl或者Foo是一個接口,反正。另外,我認爲你的意思是protected而不是private

如果你需要覆蓋protected方法,你將需要去你的第一個方法。

+0

我看到'Foo'的'final'(無論可見性)和'private'方法的問題是,如果調用它們,它們將是超類的方法,並將在我的類的超類片段的上下文中運行將'wrappedImpl'對象的狀態等用於真正的工作。因此,重寫的方法依賴於'wrappedImpl'的狀態,但未覆蓋的方法依賴於我的'FooWrapper'對象的實例的超類片段的狀態。 – QuantumMechanic

+0

最終和私有方法不能在impl中重寫。或者,所以這不應該是一個問題。受保護的方法有點訣竅,但是如果您將_always_委託給impl。(1),則將調用impl。的受保護版本(來自impl。的所謂的公用方法)。 (1)調整返回值不計;確實,您將不得不重寫抽象基類的_all_ public/protected非final方法,以確保對impl進行正確的委派。 – Attila