Наследовать от класса или абстрактного класса - PullRequest
20 голосов
/ 02 марта 2009

Если у вас есть несколько классов, которые вы хотите, чтобы они наследовали от базового класса для общей функциональности, следует ли реализовать базовый класс, используя класс или абстрактный класс?

Ответы [ 11 ]

39 голосов
/ 02 марта 2009

Это зависит от того, если вы не хотите создавать экземпляр базового класса, сделайте его абстрактным. В противном случае оставьте это как обычный класс.

16 голосов
/ 02 марта 2009

Если базовый класс не должен создаваться, тогда сделайте его абстрактным классом - если базовый класс нужно создать, не делайте его абстрактным.

В этом примере имеет смысл сделать базовый класс абстрактным, поскольку базовый класс не имеет конкретного значения:

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() { }
}

На самом деле все это довольно субъективно - вы должны быть в состоянии сделать довольно здравый смысл, исходя из потребностей вашего конкретного домена.

6 голосов
/ 02 марта 2009

Зависит от того, имеет ли смысл, что рассматриваемый базовый класс существует сам по себе, не будучи выведенным из него? Если ответ «да», то это должен быть обычный класс, в противном случае это должен быть абстрактный класс.

4 голосов
/ 02 марта 2009

Я предлагаю:

  • Сделать интерфейс.
  • Реализуйте интерфейс в вашем базовом классе.
  • Сделайте базовый класс реальным, а не абстрактным (см. Ниже, почему).

Причина, по которой я предпочитаю реальные классы, а не абстрактные классы, заключается в том, что абстрактные классы не могут быть созданы, что ограничивает будущие опции без необходимости . Например, позже мне могут понадобиться состояние и методы, предоставляемые базовым классом, но они не могут наследовать и не требуют реализации интерфейса; если базовый класс абстрактный, мне не повезло, но если базовый класс является обычным классом, я могу создать экземпляр базового класса и сохранить его как компонент моего другого класса, а затем делегировать экземпляру для повторного использования предоставленные состояние / методы.

Да, это случается не часто, но дело в том, что абстракция базового класса предотвращает повторное использование / решение такого рода, когда для этого нет оснований.

Теперь, если создание базового класса будет каким-то образом опасным, то сделайте его абстрактным - или, по возможности, сделайте его менее опасным; -)

3 голосов
/ 17 января 2010

Думайте об этом как о банковском счете:

Вы можете создать общую абстрактную базовую учетную запись, которая называется «Учетная запись», в которой содержится основная информация, например данные клиента.

Затем вы можете создать два производных класса под названием «SavingAccount» или «DebitAccount», которые могут иметь свое собственное специфическое поведение, в то же время извлекая выгоду из поведения базового класса.

Это ситуация, когда клиент должен иметь либо Сберегательный, либо Дебетовый счет, общий «Счет» не разрешен, так как в реальном мире не очень популярно иметь только учетную запись без описания.

Если вы можете создать аналогичный сценарий для своих нужд, абстрактным является путь.

1 голос
/ 02 марта 2009

Думайте об этом по-другому

Является ли мой базовый класс законченным объектом?

Если ответ отрицательный, сделайте его абстрактным. Если да, то вы, вероятно, захотите сделать это конкретным классом.

1 голос
/ 02 марта 2009

Абстрактные классы предназначены для частично реализованных классов.

Сам по себе не имеет смысла иметь экземпляр абстрактного класса, его нужно получить. Если вы хотите иметь возможность создавать базовый класс, он не может быть абстрактным.

Мне нравится думать об абстрактных классах как об интерфейсах, в которых некоторые члены предварительно определены, поскольку они являются общими для всех подклассов.

0 голосов
/ 31 марта 2011

Я думаю, что многие из вас должны снова пройти базовые ОО классы.

Основной принцип, лежащий в основе OOA / OOD, состоит в том, чтобы абстрагировать абстрактное резюме до тех пор, пока вы больше не сможете абстрагироваться. Если то, на что вы смотрите, является абстракцией, то пусть так и будет, это то, что ваш OOA / OOD уже сказал вам. Однако, если вы сидите и гадаете, должен ли «код» быть абстрактным или нет, то вы, очевидно, не знаете, что означает этот термин, и вам следует снова изучить базовый OOA / OOD / OOP: -)

Более того, вы должны изучить Шаблоны проектирования и Теорию гармоник, это очень поможет при разработке ОО!

0 голосов
/ 02 марта 2009

Абстрактные классы отлично подходят для предопределенной функциональности, например, когда известно минимальное точное поведение, которое должен представлять класс, но не то, какие данные он должен использовать для этого или точную реализацию.

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. И, конечно, вы можете смешивать и сочетать все вышеперечисленное по своему вкусу. Не существует определенного правильного пути, но мне нравится определять интерфейсы и абстрактные классы, а затем обращаться к интерфейсам. Этот способ устраняет некоторые мыслительные требования для «слесарного дела» в классах более высокого уровня, сохраняя при этом максимальную гибкость. (наличие интерфейсов снимает требование использования абстрактного базового класса, но оставляет его в качестве опции).

0 голосов
/ 02 марта 2009

Зависит от того, хотите ли вы, чтобы базовый класс был реализован сам по себе или нет.

Как абстрактный класс, вы не можете создавать из него объекты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...