Что такое абстрактный класс?

Когда я узнал об абстрактных классах, говорят WT (H *)!!!

ВОПРОСЫ:

  • В чем смысл создания класса, который не может быть создан?
  • Почему кому-то нужен такой класс?
  • Какова ситуация, когда абстрактные классы становятся НЕОБХОДИМЫМИ?

**, если вы знаете, что я имею в виду *

Ответ 1

  • чаще всего служит базовым классом или интерфейсом (некоторые языки имеют отдельный конструктор interface, а некоторые нет) - он не знает реализацию (то есть предоставляемые подклассами/реализующими классами)
  • абстракция и повторное использование
  • когда базовый класс не может обеспечить значимую реализацию по умолчанию для метода (но позволяет подклассам повторно использовать не абстрактные части реализации, любые поля, не абстрактные методы и т.д.)

Например:

public abstract class Stream { /* lots of code, some abstract methods */ }

Какая черта - это поток сам по себе? Какой поток? поток в файл? сеть? буфер памяти? Каждый может иметь разные и несвязанные способы чтения/записи, но предоставлять общий API. Это означает, что нет смысла создавать только Stream, но через класс abstract вы можете закодировать API Stream, не зная деталей:

Stream s = CreateStream(...); // I don't *care* what kind of stream
s.Write(new byte[] {1,2,3,4,5});
s.Close();

Ответ 2

Абстрактные (базовые) классы дают полубетонные классы для реализации иерархии классов. Они позволяют вам делать несколько вещей:

  • Консолидация общего поведения (в отличие от интерфейса, который определяет только контракт)
  • Предоставление возможностей по умолчанию (и, возможно, переопределяемых) для функций
  • Предоставить четко определенные точки ветвления для иерархии наследования
  • Контрольные точки ввода IoC

Список продолжается.

Ответ 3

1) В чем смысл создания класса, который не может быть создан?

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

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

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

2) Почему кому-то нужен такой класс

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

3) Какова ситуация, в которой нужны абстрактные классы?

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

Ответ 4

Цель состоит в том, чтобы указать методы, которые производные классы должны реализовать, так же, как интерфейс, но также обеспечить часть реализации (которую интерфейс не может сделать). Абстрактные классы никогда, строго говоря, "необходимы", но они полезны. Просто найдите в них стандартную библиотеку .NET или Java и убедитесь сами, как они используются. Вы найдете множество примеров.

Ответ 5

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

Ответ 6

Просто для того, чтобы скрыть фактическую реализацию от клиента, который его использует.

  • Он предоставляет реализацию concerete для определенной функциональности, и это не может быть напрямую инстанцировано
  • Доступ к ним будет доступен только из классов, которые его реализуют.
  • Таким образом, клиенты, потребляющие производный класс, никогда не узнают реализацию функциональности, потому что ее абстрагируются.

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

interface ILogger
{
    string PrepareLog(System.Exception ex);
    void InitializeLogger(string Type);
    int WriteLog(string msg);
}

Любой клиент протоколирования реализует этот интерфейс, чтобы реализовать всю эту функциональность

 class EventLogger : ILogger
{
    public override void InitializeLogger(string Type)
    {
        //Event Logger Initialize   
    }
    public override int WriteLog(string msg)
    {
        //Write to event log
        return 1;
    }
    public override string PrepareLog(System.Exception ex)
    {
      return ex.StackTrace ;
    }
}

class FileLogger : ILogger
{
    public override void InitializeLogger(string Type)
    {

    }
    public override int WriteLog(string msg)
    {
        //Write to File
        return 1;
    }
    public override string PrepareLog(System.Exception ex)
    {
      return ex.StackTrace ;
    }
}


class MailLogger : ILogger
{
    public override void InitializeLogger(string Type)
    {

    }
    public override int WriteLog(string msg)
    {
        //Write to mail
        return 1;
    }

    public override string PrepareLog(System.Exception ex)
    {
        //prepare HTML Formatted msg
        return ex.StackTrace ;
    }
}

И классы EventLogger, FileLogger и maillogger реализуют iLogger и предоставляют реализацию Контекст. Теперь мы хотели скрыть фактическую реализацию PrepareLog, и это обеспечит общую работу по подготовке сообщения журнала из объекта исключения.

В нашей текущей реализации мы не имеем возможности сделать конкретный конкретный метод, а другие - просто контрактами.

поэтому позволяет немного изменить реализацию с абстрактными классами

abstract class AbstractLogger:ILogger
{
    #region ILogger Members

    public virtual string PrepareLog(System.Exception ex)
    {
        return ex.StackTrace;
    }

    public abstract void InitializeLogger(string Type);
    public abstract int WriteLog(string msg);

    #endregion
}


class EventLogger : AbstractLogger
{
    public override void InitializeLogger(string Type)
    {
        //Event Logger Initialize   
    }
    public override int WriteLog(string msg)
    {
        //Write to event log
        return 1;
    }
}

class FileLogger : AbstractLogger
{
    public override void InitializeLogger(string Type)
    {

    }
    public override int WriteLog(string msg)
    {
        //Write to File
        return 1;
    }
}

class DBLogger : AbstractLogger
{
    public override void InitializeLogger(string Type)
    {

    }
    public override int WriteLog(string msg)
    {
        //Write to DB
        return 1;
    }
}

class MailLogger : AbstractLogger
{
    public override void InitializeLogger(string Type)
    {

    }
    public override int WriteLog(string msg)
    {
        //Write to mail
        return 1;
    }

    public override string PrepareLog(System.Exception ex)
    {
        //prepare HTML Formatted msg
        return ex.StackTrace ;
    }
}

Теперь я создал класс AbstractLogger, который наследует от iLogger и реализовал только метод PrepareLog, остаточные методы оставлены абстрактными. поэтому потребители напишут контекстный код в своей реализации.

Итак, теперь метод PrepareLog полностью скрыт (что означает подготовку журнала) от косуммеров, инициализированных любым из Loggers.

то почему PrepareLog является Virtual ed?

Есть сценарии, которые потребитель может захотеть переопределить метод preparelog, Ex: MailLogger переопределит PrepareLog и отформатирует вывод в формате HTML для доставки почтовых сообщений.

Ответ 7

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

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

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

Сотовый телефон является сотовым телефоном, а подклассы абстрактного класса - это абстрактный класс.

Ответ 8

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

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

Ответ 9

Точкой абстрактного класса является определение (ограничение) вашего интерфейса без описания реализации.

  • Абстрактный класс может быть создан путем создания совместимого объекта с производным типом класса.

  • Чтобы реализовать чистый интерфейс, который скрывает уродливый код конкретной платформы. Также скрывать рядовых от любого вида воздействия. (Чтобы вы действительно были вынуждены использовать класс с абстрактным интерфейсом.)

  • Это необходимо, если у вас есть две разные реализации одного и того же класса, которые радикально отличаются друг от друга. Подумайте о файле, сокете и блоке памяти. Все они могут сделать доступными доступные для чтения данные - используя абстрактный класс, вы можете реализовать эти три по-разному, даже если используемый код (call-sites) написан одним из способов поддержки всех трех.

Ответ 10

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

В общем, предпочитают интерфейсы. Абстрактные классы полезны, когда у вас есть дерево наследования, которое имеет общие операции, которые будут использоваться дочерними классами. Но даже здесь вы можете заявить, что ваш абстрактный класс реализует интерфейс. Джош Блох называет это "абстрактным интерфейсом". Это позволяет развертывать различные реализации даже абстрактного класса, что парадоксально на самом деле не полностью абстрактно - только интерфейсы.

Ответ 11

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

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

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

Ответ 12

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

Ответ 13

То же, что и с интерфейсами, абстрактный класс - это контракт, в котором вы предоставили некоторые общие (или абстрактные) функциональные возможности, применимые ко многим сценариям, но ожидайте, что разработчик предоставит некоторую функциональность, которая специфические и/или разные для каждого сценария. Кто-то упомянул пример Stream - очень хороший пример.