2013-02-24 46 views
15

我有一個父類,它定義了一個chainer方法(返回「this」的方法)的集合。我想要定義多個包含自己的chainer方法的子類,但也要「覆蓋」父方法,以便返回子類的實例而不是父類。Java中的OOP:使用方法鏈接進行類繼承

我不想在每個子類中重複相同的方法,這就是爲什麼我有一個包含所有子類共享方法的父類。謝謝。

class Chain { 
    public Chain foo(String s){ 
    ... 
    return this; 
    } 
} 

class ChainChild extends Chain { 
    //I don't want to add a "foo" method to each child class 
    /* 
    public ChildChain foo(String s){ 
    ... 
    return this; 
    } 
    */ 

    public ChainChild bar(boolean b){ 
    ... 
    return this; 
    } 
} 

ChainChild child = new ChainChild(); 
child.foo().bar(); //compile error: foo() returns a "Chain" object which does not define the bar() method. 
+1

可能重複的[我可以有一個抽象的生成器類在Java與方法鏈接,而不做不安全的操作?](http://stackoverflow.com/questions/5818504/can-i-have-an-abstract-builder- java-with-method-chaining-without-doing) – artbristol 2013-02-24 17:19:20

+0

我很好奇,在什麼情況下使用這樣的('child.foo().bar();')調用? – vijay 2013-02-24 17:23:09

+0

@vijay有一些設置,所有的子類都可以使用。例如,一個方法需要一個布爾參數來啓用/禁用某個設置。 – Michael 2013-02-24 17:30:03

回答

13

在返回this仍然會返回引用到子類的對象的父類的方法。您只能將其視爲父類的對象(除非您投了它),但它實際上會是其原始類型。

你可以考慮使用泛型這樣的:

// This seems a bit too contrived for my liking. Perhaps someone else will have a better idea. 
public class Parent<T extends Parent<T>> { 
    T foo() { 
     return (T) this; 
    } 
} 

public class Child extends Parent<Child> { 
    public void bar() { 
     Child c = foo(); 
    } 
} 
+0

我意識到這一點。但問題是,即使它是同一個對象,我也無法調用子類中的方法,因爲該對象是作爲父類進行類型化處理的。 – Michael 2013-02-24 17:18:07

+2

我認爲@ luiggi的技術可能會更整潔。 – OldCurmudgeon 2013-02-24 17:27:10

0

您可以只投它。

ChainChild child = new ChainChild(); 
((ChainChild) child.foo()).bar(); 

你可以嘗試:

public ? extends Chain foo() { 
    return this; 
} 

但我不知道這將有助於,即使它編譯。

+0

Ewww醜。我不想投它:) – Michael 2013-02-24 17:19:56

+0

'?擴展「可能工作,但我不確定 - 實質上,您正在嘗試假設隱藏於您的信息,作爲封裝基礎的一部分。 – 2013-02-24 17:21:58

+2

第二個案例不會編譯 – 2013-02-24 17:22:23

10

我已經根據您的需求使用泛型編寫了此示例。

class Parent { 
    public <T extends Parent> T foo() { 
     return (T)this; 
    } 
} 

class Child extends Parent { 

} 

class AnotherChild extends Parent { 

} 

public class Test { 
    public static void main(String[] args) { 

     Parent p = new Child(); 
     System.out.println(p); 
     Child c = p.foo(); 
     System.out.println(c); 
     //throws ClassCastException here since Child is not AnotherChild 
     AnotherChild ac = p.foo(); 
     System.out.println(ac); 
    } 
} 
+0

嗯,不錯,雖然技術上它只是在演員陣容發生移動。 – 2013-02-24 20:52:40

+0

@PhilipWhitehouse這就是OP正在尋找的東西。 – 2013-02-24 20:56:00

+0

這裏的問題是T是從變量聲明中推斷出來的,而不是從類本身推斷出來的。 – d4n3 2013-05-14 10:25:03

1

這裏有OldCurmudgeon的方法的改進:

public class Parent<This extends Parent<This>> { 

    @SuppressWarnings("unchecked") 
    private final This THIS = (This)this; 

    public This foo() { 
     //... 
     return THIS; 
    } 

    public This bar() { 
     //... 
     return THIS; 
    }  
} 

public class Child extends Parent<Child> { 

    // you can override super with covariant return type 
    @Override 
    public Child bar() { 
     super.bar(); 

     return this; 
    } 
} 


Child child = 
new Child() 
.foo() 
.bar(); 

的改善正在一個未經檢查只投了一次,並將其保存到一個恆定這一點,這可以重用爲方法鏈的返回值。

這將刪除每個方法中的未檢查強制轉換,並使代碼更清晰。

您可以通過返回Child而不是this(協變返回類型)來覆蓋Parent的方法。