簡體   English   中英

從類或抽象類繼承

[英]Inherit from a class or an abstract class

如果你有幾個類希望它們從基類繼承以獲得通用功能,那么你應該使用類還是抽象類來實現基類?

這取決於,如果您從未希望能夠實例化基類,那么請將其抽象化。 否則將其保留為普通班級。

如果基類不應該被實例化,那么使它成為一個抽象類 - 如果基類需要實例化,那么不要使它抽象。

在這個例子中,使基類抽象是有意義的,因為基類沒有任何具體含義:

abstract class WritingImplement
{
    public abstract void Write();
}

class Pencil : WritingImplement
{
    public override void Write() { }
}

但是在下一個示例中,您可以看到基類如何具有具體含義:

class Dog
{
    public virtual void Bark() { }
}

class GoldenRetriever : Dog
{
    public override void Bark() { }
}

這一切都非常主觀 - 你應該能夠根據你的特定領域的需求做出一個非常好的判斷。

這取決於,有問題的基類是否有意義存在於它自己而不是從中派生出來? 如果答案是肯定的,那么它應該是一個普通的類,否則,它應該是一個抽象類。

我建議:

  • 建立一個界面。
  • 在基類中實現接口。
  • 使基類成為一個真正的類,而不是抽象的(見下面的原因)。

我更喜歡真正的類而不是抽象類的原因是抽象類無法實例化,這不必要地限制了未來的選項。 例如,稍后我可能需要基類提供的狀態和方法但不能繼承而不需要實現接口; 如果基類是抽象的我運氣不好,但如果基類是常規類,那么我可以創建基類的實例並將其作為我的其他類的一個組件,並委托給實例重用提供的州/方法。

是的,這不會經常發生,但關鍵是:當沒有理由這樣做時,使基類抽象可以防止這種重用/解決方案。

現在,如果實例化基類會以某種方式危險,那么將其抽象化 - 或者最好使其不那么危險,如果可能的話;-)

把它想象成一個銀行賬戶:

您可以創建一個名為“帳戶”的通用抽象基本帳戶,它包含客戶詳細信息等基本信息。

然后,您可以創建兩個名為“SavingAccount”或“DebitAccount”的派生類,這些類可以具有自己的特定行為,同時受益於基類行為。

在這種情況下,客戶必須擁有儲蓄賬戶或借記賬戶,不允許使用通用的“賬戶”,因為在現實世界中僅僅擁有一個沒有描述的賬戶並不是很受歡迎。

如果您可以根據需要創建類似的場景,那么抽象是可行的方法。

抽象類用於部分實現的類。

擁有一個抽象類的實例本身沒有意義,它需要派生。 如果您希望能夠創建基類,則它不能是抽象的。

我喜歡將抽象類視為具有一些預定義成員的接口,因為它們對所有子類都是通用的。

以不同的方式考慮這一點

我的基類是否是它自己的完整對象?

如果答案是否定的,則將其抽象化。 如果是,那么你可能想把它變成一個具體的類。

我會說如果你不打算單獨調用基類,那么你應該將它定義為抽象類。

這取決於您是否希望基類自行實現。

作為抽象類,您無法從中創建對象。

抽象類非常適合預定義的功能,例如 - 當知道類應該暴露的最小確切行為但不知道應該使用什么數據來執行它或確切的實現。

abstract class ADataAccess
{
    abstract public void Save();
}

普通(非抽象)類可以用於類似的事情,但是你必須知道能夠編寫它們的實現細節。

public class DataAccess
{
    public void Save()
    {
        if ( _is_new )
        {
            Insert();
        }
        else if ( _is_modified )
        {
            Update();
        }
    }
}

此外,您可以使用接口(單獨或在類上,無論是否為抽象)來定義相同類型的原型定義。

interface ISaveable
{
    void Save();
    void Insert();
    void Update();
}

class UserAccount : ISavable
{
    void ISavable.Save() { ... }
    void ISavable.Insert() { ... }
    void ISavable.Update() { ... }
}

另一種選擇可能是使用泛型

class GenDataAccess<T>
{
    public void Save()
    {
        ...
    }
}

所有這些方法都可用於為要使用的類定義某個原型。 如何確保代碼A可以與代碼B交談。當然,您可以根據自己的喜好混合和匹配以上所有內容。 沒有明確的正確方法,但我喜歡定義接口和抽象類,然后參考接口。 這樣就消除了更高級別的“管道”的一些思想要求,同時保持了最大的靈活性。 (讓接口消除了使用抽象基類的要求,但將其留作選項)。

我想很多人應該再次重新啟用基本的OO課程。

OOA / OOD的基本原理是抽象抽象抽象,直到你不能抽象為止。 如果你所看到的是一個抽象,那就這樣吧,那就是你的OOA / OOD告訴你的。 但是,如果你坐在那里想知道“代碼”是否應該是抽象的,那么你顯然不知道該術語的意思,應該再次學習基本的OOA / OOD / OOP :-)

更重要的是,您應該學習設計模式和諧波理論,這將極大地幫助您的OO設計!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM