Наследовать от класса или абстрактного класса

StackOverflow https://stackoverflow.com/questions/603661

  •  03-07-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

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

Другие советы

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

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

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

Все эти методы можно использовать для определения определенного прототипа классов, с которыми будут работать.Способы убедиться, что код А может общаться с кодом Б.И, конечно же, вы можете комбинировать все вышеперечисленное по своему вкусу.Не существует однозначно правильного способа, но мне нравится определять интерфейсы и абстрактные классы, а затем обращаться к интерфейсам.Таким образом, устраняются некоторые мыслительные требования к «сантехнике» на занятиях более высокого уровня, сохраняя при этом максимальную гибкость.(наличие интерфейсов устраняет необходимость использования абстрактного базового класса, но оставляет это как вариант).

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top