2016-02-07 3 views
33

Я прочитал, что с помощью Scala обычно рекомендуется использовать черты вместо абстрактных классов для расширения базового класса.Состав клиента Scala с чертами по сравнению с абстрактным классом

Является ли следующий хороший дизайн и макет дизайна? Так ли, как Черты были предназначены для замены Abstract?

  • клиент класса (с четкости function1)
  • trait1 класса (переопределение function1)
  • trait2 класса (переопределение function1)
  • specificClient1 расширяет клиент с trait1
  • specificClient2 расширяет клиент с trait2

ответ

66

Я не знаю, каков ваш источник для утверждения о том, что вы предпочитаете черты над абстрактными классами в Scala, но повторно несколько причин не к:

  1. Черты характера усложнит совместимость Java. Если у вас есть черта с объектом-компаньоном, методы вызова на сопутствующем объекте из Java требуют бизарного MyType$.MODULE$.myMethod синтаксиса. Это не относится к абстрактным классам с сопутствующими объектами, которые реализуются на JVM как один класс со статическими и экземплярами. Реализация признака Scala с конкретными методами в Java еще более неприятна.
  2. Добавление метода с реализацией к признаку breaks binary compatibility таким образом, что добавление конкретных методов в класс не выполняется.
  3. В результате получается больше байт-кода и некоторые дополнительные накладные расходы, связанные с использованием методов пересылки.
  4. Черты более мощные, что плохо - в общем, вы хотите использовать наименее мощную абстракцию, которая выполняет свою работу. Если вам не требуется такое многократное наследование, которое они поддерживают (и очень часто это не так), лучше не иметь к нему доступа.

Последняя причина, безусловно, самая важная на мой взгляд. По крайней мере, несколько других проблем might get fixed в будущих версиях Scala, но это останется тем, что по умолчанию классы будут ограничивать ваши программы способами, которые (по крайней мере, возможно) согласуются с хорошим дизайном. Если вы решите, что на самом деле действительно хотите силу, присущую чертам, они все равно будут там, но это будет ваше решение, а не то, что вы просто вскочите.

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

+2

В качестве сноски подход Scala к линеаризации _is_ является умным решением проблемы «множественного наследования», и когда вам это нужно, он работает достаточно хорошо (за исключением нескольких вещей, таких как поля). Но вы никогда не должны использовать что-то только потому, что это умно. –

+1

Спасибо, что отвечает на мой вопрос. Мой источник был https://www.safaribooksonline.com/library/view/scala-cookbook/9781449340292/ch04s13.html. Ваш ответ имеет больше смысла. – kliew

+1

С Scala [2.12] (http://www.scala-lang.org/news/2.12.0) # 1-3 по-прежнему применяются vis-a-vis '". интерфейс с методами по умолчанию, что улучшает совместимость с двоичными файлами и совместимость с Java. Конечно, №4 - причина, по которой я думаю, достаточно выбрать «абстрактный класс» над «чертой». @TravisBrown –

2

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

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

Смежные вопросы