2009-11-04 103 views
4

從具體子類中抽象類中提供值的「正確」方式是什麼?從子類中提供抽象類成員變量

即,我應該這樣做:

abstract class A { 
    private string m_Value; 

    protected A(string value) { 
     m_Value = value; 
    } 

    public string Value { 
     get { return m_Value; } 
    } 
} 

class B : A { 
    B() : this("string value") {} 
} 

或本:

abstract class A { 

    protected A() { } 

    public abstract string Value { get; } 
} 

class B : A { 
    B() {} 

    public override string Value { 
     get { return "string value"; } 
    } 
} 

或其他什麼東西?

如果僅在抽象類中使用Value屬性,應該做不同的事情嗎?

回答

1

我通常更喜歡第一種方法,因爲它需要較少的子類代碼。

但是,我承認第二種方法的語義更加清晰細膩。覆蓋屬性說「這個屬性的實現是我的身份的一部分。」傳遞構造函數參數具有不同的含義:「我爲這個其他的東西設置了一個值,這恰好是我的基類。」它意味着構成(has-a)而不是繼承(is-a)。

如果 Value屬性只在 抽象類應使用不同的東西做什麼?

在這種情況下,您應該使用第一種(基於構造函數的)方法,以便您可以從子類中隱藏該實現細節。

同樣,如果您需要使用構造函數中的值;作爲Marc mentioned這是使用第一種方法的實際技術原因。雖然在這種特定情況下無關緊要,但如果稍後某人修改了屬性重寫以在派生類中使用某些其他成員變量,那麼您可能手上有一個微妙的錯誤。

1

這取決於;基地級需要在ctor中瞭解它嗎?如果是這樣,override的做法可能是一個壞主意(virtual在ctor內部不能很好地工作)。否則,任何一個都可以。

1

我認爲第二個習語更好,因爲它更易於管理(如果您的基類需要派生類中定義的多個屬性,構造函數會變得雜亂)。信息來源的地方也更清楚。如果您看到Value屬性,那麼您知道它是在子類中定義的。在第一個示例中,您必須跟蹤m_Value變量的定義點,該變量可以在基類中修改。

1

我認爲它幾乎是一樣的,選擇一種方式,並堅持一致。

這兩個解決方案都迫使派生類提供一個值,這是很好的;一種可能的替代,如果不應該要求一個值:

abstract class A { 
    public string Value { 
     get; 
     protected set; 
    } 
} 

我個人的偏好是您的第一選擇(構造函數參數),因爲我個人認爲它是更清晰的一個,但它是真正的喜好問題。

1

這取決於。

如果我需要修改抽象類中的Value,我將使用第一種方法。

只有當我需要從A和某處繼承很多類時,纔會使用第二種方法,我需要將繼承的類裝箱到基本抽象類。

如果上述兩個都不正確,我將使用第二種方法,它更易於管理和清潔。

如果Value僅用於抽象類,我將聲明它爲private而不是屬性。

0

第二種情況的一個主要優點是它允許子類爲Value屬性定義行爲,該屬性可能比簡單的標量值更復雜。例如,您可能想根據子類定義的其他字段來計算值。採用第一種方法,這是不可能的,但第二種方法允許這樣做。

+0

您可以通過聲明虛擬屬性來實現第一種方法。 – 2009-11-04 16:49:30

0

我更喜歡第二個。如果值是常量或者可以在運行時計算,它可以讓您提供一個值,而無需向類中添加實際字段。您擁有的狀態越少(字段越少),您可能會發現該代碼的可維護性越高。