abstract class vs Interface

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by BrainDeaD, 13 Mar 2010.

  1. BrainDeaD

    BrainDeaD Elder - Старейшина

    Joined:
    9 Jun 2005
    Messages:
    774
    Likes Received:
    292
    Reputations:
    214
    Доброго времени суток уважаемые кодеры и не только.

    Сегодня я решил написать небольшую статейку, в которой пойдёт речь о интерфейсах и абстрактных классах в языке C#.

    Тем из вас, кто имеет хоть немного опыта в C#, уже вероятно известно о существовании таких понятий как abstract class и Interface, и что оба могут быть реализованы или унаследованы другими классами. Вы возможно так-же задавались вопросом "что и в каких случаях использовать?".


    Что-ж, давайте для начала рассмотрим, в чём состоят основные отличия данных классов.

    Interface

    - все члены должны быть реализованы.
    - содержит только открытые члены.
    - один класс может реализовывать несколько интерфейсов.
    - не изменяем. Т.е. при изменении интерфейса придётся изменять весь, от него зависящий, код.
    - описывает поведение "has-a"(содержит).

    abstract class

    - может сам содержать реализацию.
    - возможна принудительная реализация для дочернего класса с помощью модификатора abstract.
    - возможна опциональная реализация для дочернего класса с помощью модификатора virtual.
    - не поддерживает множественного наследования.
    - может быть изменён, хотя и с некоторыми ограничениями.
    - описывает поведение "is-a"(является).


    Так что-же и когда использовать?

    Представим себе, что мы программируем движок варез-портала.
    Один из наших классов называется Content от которого наследуют классы Post, Comment, Download.

    Должен ли наш базовый класс Content быть абстрактным?

    Так как мы в нашем движке класс Content не используем, то есть никогда не создаём объект данного типа (это было бы бессмысленно, ведь понятие Content не выражает никакого конкретного смысла в отличии от Post, Comment и Download) следует сделать его абстрактным.
    В таком случае наш базовый класс используется для полиморфного поведения дочерних классов.

    Теперь добавим нашему классу Content немного функционала и определим в нём метод Edit().

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

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

    В итоге можно отметить, что в большинстве случаев стоит отдать предпочтение абстрактным классам.


    Для принятия решения в каком случае какой тип более подходящий, можно воспользоваться такой цепочкой решений:

    Имея базовый класс для группы схожих классов
    нас интересуют тответы на вопросы:

    Используется ли сам класс как логическая единица? То есть инстанцируем ли мы его.
    Если да: используем обыкновенный класс.
    Если нет: используем абстрактный класс.

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


    Источники:
    msdn.microsoft.com
    seregaborzov.wordpress.com
    aspnetzone.de
    csharp-online.net
     
    3 people like this.