Проблема

Решение

  1. Подклассы должны быть специализациями.
  2. Рефакторинг иерархий.
  3. Отдайте предпочтение композиции.
  4. Классы листьев должны быть конкретными.
  5. Неконечные классы должны быть абстрактными.

Образец кода

Неправильный

class Stack<T> : ArrayList<T>() {
    fun push(value: T) { … }
    fun pop(): T { … }
}
// Stack does not behave Like an ArrayList
// besides pop, push, top it also implements (or overrides) get, set,
// add, remove and clear stack elements can be arbitrary accessed
// both classes are concrete

Верно

abstract class Collection {
    abstract fun size(): Int
}

class Stack<out T> : Collection() {
    private val contents = ArrayList<T>()

    fun push(value: Any) { ... }

    fun pop(): Any? { ... }

    override fun size() = contents.size
}

class ArrayList : Collection() {
    override fun size(): Int { ... }
}

Заключение

Случайная подклассификация — первое очевидное преимущество младших разработчиков.

Вместо этого более зрелые находят возможности для композиции.

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

Разделяйте сущность на подклассы только в том случае, если она соответствует отношению ведёт себя как.

После создания подклассов родительский класс должен быть абстрактным.

Java допустила эту ошибку, и они сожалеют об этом до сих пор. Давайте сделаем лучше, чем Java 😁

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

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

Кредиты

Оригинально опубликовано на https://yonatankarp.com.