Что такое абстрактный класс? Что такое интерфейс?android-29

Абстрактный класс

Абстрактный класс — это класс, который не может быть инстанциирован напрямую и предназначен для наследования. Он может содержать как абстрактные (без реализации), так и конкретные методы.

Характеристики:

abstract class Animal(
    protected val name: String  // Абстрактный класс может иметь свойства
) {
    // Абстрактный метод (без реализации)
    abstract fun makeSound()

    // Обычный метод с реализацией
    fun eat() {
        println("$name is eating")
    }
}

class Dog(name: String) : Animal(name) {
    override fun makeSound() {
        println("$name says: Woof!")
    }
}

Когда использовать:

  1. Когда нужно предоставить базовую реализацию для подклассов
  2. Для создания семейств связанных классов
  3. Если требуется контроль над состоянием (полями класса)

Интерфейс

Интерфейс — это контракт, который определяет, что класс должен делать, но не как он должен это делать. С Kotlin 1.4 интерфейсы могут иметь реализацию методов (default-методы).

Характеристики:

interface ClickListener {
    fun onClick()  // Абстрактный метод

    // Метод с реализацией (default метод)
    fun onLongClick() {
        println("Default long click behavior")
    }
}

class Button : ClickListener {
    override fun onClick() {
        println("Button clicked")
    }
    // onLongClick не обязательно переопределять
}

Когда использовать:

  1. Для определения поведения, которое могут реализовывать несвязанные классы
  2. Когда нужно обеспечить множественное наследование поведения
  3. Для создания API без привязки к конкретной реализации

Ключевые различия

Характеристика Абстрактный класс Интерфейс
ИнстанциированиеНельзя создать экземплярНельзя создать экземпляр
СостояниеМожет содержать поляМожет содержать свойства (но без backing field)
КонструкторыМожет иметь конструкторыНе может иметь конструкторов
Множественное наследованиеНет (только один абстрактный класс)Да (можно реализовать несколько интерфейсов)
Модификаторы доступаМожет иметь protected членыВсе члены public (по умолчанию)
Default-методыВсегда мог иметь реализованные методыС Kotlin 1.4 может иметь реализацию

Современные практики в Android

  1. Использование интерфейсов для View-контрактов:
interface MainView {
    fun showProgress()
    fun hideProgress()
    fun showData(data: List<Item>)
}

class MainActivity : AppCompatActivity(), MainView {
    override fun showProgress() { /* ... */ }
    // ...
}
  1. Абстрактные классы для базовых компонентов:
abstract class BaseActivity : AppCompatActivity() {
    abstract val layoutRes: Int

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(layoutRes)
        setupViews()
    }

    protected open fun setupViews() {}
}

class MainActivity : BaseActivity() {
    override val layoutRes: Int = R.layout.activity_main

    override fun setupViews() {
        // Инициализация UI
    }
}
  1. Комбинация абстрактных классов и интерфейсов:
interface Repository<T> {
    fun add(item: T)
    fun get(id: String): T?
}

abstract class BaseRepository<T> : Repository<T> {
    protected val items = mutableListOf<T>()

    override fun add(item: T) {
        items.add(item)
    }

    override fun get(id: String): T? {
        return items.find { /* логика поиска */ }
    }
}

Эволюция в Kotlin

  1. Интерфейсы с реализацией:
interface Printer {
    fun print() {
        println("Printing...")
    }
}

class Document : Printer {
    // Можно не переопределять print()
}
  1. Делегирование интерфейсов:
interface Engine {
    fun start()
}

class ElectricEngine : Engine {
    override fun start() { println("Electric engine started") }
}

class Car(engine: Engine) : Engine by engine  // Делегирование

Резюмируем:

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