Вот сколько лет я ни пишу код, без конца убеждаюсь в двух вещах:
1. Если стоит выбор между мутабельностью и иммутабельностью — без раздумий выбирай иммутабельность.
2. Если стоит выбор между наследованием и композицией — без раздумий выбирай композицию.
Каждый раз, когда я выбираю мутабельность, я получаю хрупкую программу с непредсказуемыми сайд-эффектами.
Каждый раз, когда я выбираю наследование, я получаю запутанный код, который трудно переиспользовать (хотя обещали, что будет наоборот) и невозможно читать, не прыгая по нескольки классам с полузащищённым API.
Интересно, что и мутабельность, и наследование осложняют типизацию и привносят костыли:
@self-out, @this-out, @require-extends.Я не Егор Бугаенко и не утверждаю, что мутабельность и наследование прям вот совсем не нужны. Но если есть выбор (90% случаев на моей open source практике) — советую воздерживаться.