Kotlin: зачем использовать абстрактные классы (vs. интерфейсы)?

Я знаю о двух различиях между абстрактными классами и интерфейсами в Котлине:

  • Абстрактный класс может иметь состояние (например, var …)
  • Класс может реализовывать несколько интерфейсов, но не несколько абстрактных классов.

Поскольку Котлин – довольно свежий язык, мне интересно, почему абстрактные классы не были оставлены? Интерфейсы кажутся превосходным инструментом, при этом очень мало нужны абстрактные классы.

Чтобы уточнить: Kotlin действительно поддерживает реализацию конкретных функций в интерфейсах, например:

 interface Shiny { fun shine(amount : Int) // abstract function fun reflect(s : String) { print ("**$s**") } // concrete function } 

Может ли кто-нибудь дать сильный практический пример необходимости абстрактных классов?

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

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

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

    Пример:

     interface MyContainer { var size: Int fun add(item: MyItem) { // ... size = size + 1 } } 

    Здесь мы предоставляем реализацию по умолчанию для add который увеличивает size . Но он может сломаться, если класс реализации определяется следующим образом:

     class MyContainerImpl : MyContainer { override val size: Int get() = 0 set(value) { println("Just ignoring the $value") } } 

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

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

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