В чем преимущество использования абстрактного класса вместо черты (помимо производительности)? Кажется, что абстрактные классы могут быть заменены чертами в большинстве случаев.
371
Я могу думать о двух различиях
В Scala есть раздел «Программирование, черта или нет?» который решает этот вопрос. Так как 1-е издание доступно в Интернете, я надеюсь, что все в порядке, чтобы процитировать все это здесь. (Любой серьезный программист Scala должен купить книгу):
Как упоминал @Mushtaq Ahmed, в признаке не может быть никаких параметров, передаваемых первичному конструктору класса.
Другое отличие заключается в лечении
super
.См. Остальную часть главы 12 для более подробной информации.
Изменить 1 (2013):
Существует тонкое различие в поведении абстрактных классов по сравнению с чертами. Одно из правил линеаризации состоит в том, что оно сохраняет иерархию наследования классов, которая имеет тенденцию выдвигать абстрактные классы позднее в цепочке, в то время как признаки могут быть легко смешаны. В определенных обстоятельствах на самом деле предпочтительнее находиться в последней позиции линеаризации классов Таким образом, абстрактные классы могут быть использованы для этого. Смотрите линеаризацию ограничивающего класса (порядок смешивания) в Scala .
Изменить 2 (2018):
Начиная с Scala 2.12, поведение бинарной совместимости черты изменилось. До 2.12 добавление или удаление члена для признака требовало перекомпиляции всех классов, которые наследуют признак, даже если классы не изменились. Это связано с тем, как черты кодировались в JVM.
Начиная с Scala 2.12, черты компилируются в интерфейсы Java , поэтому требования немного ослабли. Если признак выполняет одно из следующих действий, его подклассы все еще требуют перекомпиляции:
Но если этого не происходит, вы можете обновить его, не нарушая бинарную совместимость.
источник
If outside clients will only call into the behavior, instead of inheriting from it, then using a trait is fine
- Может кто-нибудь объяснить, в чем здесь разница?extends
противwith
?extends
иwith
. Это чисто синтаксический. Если вы наследуете от нескольких шаблонов, первый получаетextend
, все остальные получаютwith
, вот и все. Думайте оwith
запятойclass Foo extends Bar, Baz, Qux
.Для чего бы это ни стоило, Odersky et al. Программирование в Scala рекомендует, когда вы сомневаетесь, использовать черты. Вы всегда можете изменить их на абстрактные классы позже, если это необходимо.
источник
Помимо того факта, что вы не можете напрямую расширять несколько абстрактных классов, но вы можете смешивать несколько признаков в классе, стоит упомянуть, что признаки являются наращиваемыми, поскольку супер-вызовы в признаке динамически связаны (это относится к классу или признаку, смешанному до текущий).
Из ответа Томаса « Разница между абстрактным классом и чертой» :
источник
При расширении абстрактного класса это показывает, что подкласс имеет аналогичный вид. Я думаю, что это не обязательно так, когда используются черты.
источник
В Программировании Scala авторы говорят, что абстрактные классы создают классические объектно-ориентированные отношения «есть», в то время как черты - это scala-способ композиции.
источник
Абстрактные классы могут содержать поведение - они могут параметризоваться с помощью аргументов конструктора (что не может иметь признаков) и представлять работающий объект. Черты вместо этого просто представляют одну особенность, интерфейс одной функциональности.
источник
trait Enumerable
с большим количеством вспомогательных функций, я бы не назвал их поведением, а просто функциональностью, связанной с одной функцией.источник