Что такое абстрактный класс? [дубликат]

Этот вопрос уже имеет ответ здесь:

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

ВОПРОСЫ:

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

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

12
задан Pratik Deoghare 16 December 2009 в 05:20
поделиться

12 ответов

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

Например:

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

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

Stream s = CreateStream(...); // I don't *care* what kind of stream
s.Write(new byte[] {1,2,3,4,5});
s.Close();
16
ответ дан 2 December 2019 в 03:38
поделиться

Просто скрыть реальную реализацию от клиента, который ее использует.

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

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

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, полностью скрытый (то есть подготовка журнала) от пользователей, инициализировал любой из регистраторов.

2
ответ дан 2 December 2019 в 03:38
поделиться

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

0
ответ дан 2 December 2019 в 03:38
поделиться

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

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

1
ответ дан 2 December 2019 в 03:38
поделиться

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

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

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

8
ответ дан 2 December 2019 в 03:38
поделиться

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

2
ответ дан 2 December 2019 в 03:38
поделиться

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

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

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

5
ответ дан 2 December 2019 в 03:38
поделиться

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

2
ответ дан 2 December 2019 в 03:38
поделиться

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

Shape будет содержать код, общий для Square, Circle или Rectangle, такой как вычисление площади формы. Но создание экземпляра формы было бы бесполезным, поскольку это абстрактная концепция, а квадраты, круги и прямоугольники являются реальными объектами.

2
ответ дан 2 December 2019 в 03:38
поделиться

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

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

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

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

1
ответ дан 2 December 2019 в 03:38
поделиться

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

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

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

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

1
ответ дан 2 December 2019 в 03:38
поделиться

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

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

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

0
ответ дан 2 December 2019 в 03:38
поделиться