Композиция против наследования в Kotlin

kotlin

Composition over inheritance (and Kotlin) — небольшая заметка, хорошо иллюстрирующая принцип композиции объектов и его преимущества перед наследованием.

Взгляни на следующий код:

Это канонический пример наследования в объектно ориентированном программировании. Объект класса Grandchild сможет вызывать методы parentFunctionality() и childFunctionality(). Код красив и замечателен. Но представь себе, что будет, если сильно усложнить этот пример, добавив в каждый класс множество новых открытых методов и связав их между собой. В какой-то момент может оказаться, что ты переопределяешь метод, который используется другим методом, и таким образом ломаешь функциональность всего объекта.

Разумеется, грамотный дизайн поможет избежать этой проблемы, но что, если команда разработчиков состоит не только из тебя одного и в коде есть множество классов с незнакомым тебе кодом?

РЕКОМЕНДУЕМ:
Хорошие и плохие приемы программирования на Kotlin

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

Предыдущий код, переписанный с использованием принципа композиции, будет выглядеть так:

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

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

РЕКОМЕНДУЕМ:
Полезные советы разработчику на языке Kotlin

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

Ну и последнее — функции-расширения, которые позволяют добавить новые методы к существующему классу без необходимости наследоваться от него:

Понравилась статья? Поделиться с друзьями:
Добавить комментарий