2014-09-25 96 views
1

類A從抽象類B派生並實現了抽象方法foo。 現在在foo方法中,我想要做一些依賴於類A的成員變量mType的東西。然而,這會導致一個bug,因爲在抽象類B的構造函數中調用foo,因此mType尚未初始化。調用基類構造函數之前的初始成員變量

不可能在super()之前初始化mType,所以我不知道一個很好的和乾淨的方法來解決這個問題。當然,我可以讓mType成爲B的一員,但我認爲這不是一個好的方法,因爲mType與這個類沒有任何關係,在這個例子中這可能不是很清楚,但我當然會爲了解釋這個問題,將實際情況改寫爲簡短的實際情況。

什麼是解決這個問題的好方法?

public abstract class B { 
    public B() { 
     foo(); // A::mType IS NOT INITIALISED!! 
    } 

    protected abstract void foo(); 
} 

private class A extends B { 
    public enum Type { TYPE1, TYPE2 }; 

    public A(Type aType) { 
     super(); 
     mType = aType; 
    } 

    @Override 
    protected void foo() { 
     if (mType == Type.TYPE1) { 
      // .. 
     } else { 
      // ... 
     } 
    } 
} 
+3

[永遠不要從構造函數調用覆蓋方法](http://stackoverflow.com/questions/3404301/whats-wrong-with-overridable-method-calls-in-constructors)。 – Seelenvirtuose 2014-09-25 08:28:16

+0

您可以在構造函數中的'foo()'中執行任何設置代碼?爲什麼重寫它,如果你只是立即調用它呢? – 2014-09-25 08:29:10

+0

在構造函數中調用可重寫方法的錯誤做法,但是如果您必須*,您可以更改'foo'的簽名以獲取'foo(Type)'並執行所需的任何操作,即分配您的成員並執行其他檢查等等 – webuster 2014-09-25 08:54:55

回答

0

就Seelenvirtuose發表的評論達成一致,我會回答我的問題。在構造函數中調用可重寫的方法確實是不好的做法。下面解決了這個問題:

public abstract class B { 
    public B() { } 

    protected abstract void foo(); 

    protected void init() { 
     foo(); 
    } 
} 

private class A extends B { 
    public enum Type { TYPE1, TYPE2 }; 

    public A(Type aType) { 
     super(); 
     mType = aType; 
     init(); 
    } 

    @Override 
    protected void foo() { 
     if (mType == Type.TYPE1) { 
      // .. 
     } else { 
      // ... 
     } 
    } 
} 

乍一看也許顯得不切實際,爲什麼不直接調用foo在A類的構造函數,但在我真正的實際情況,這是相當更加複雜,各種overrided方法需要以某種順序被調用。基類需要爲此提供一種方法以避免代碼重複。添加從派生類調用的簡單init方法可解決此問題。

相關問題