2015-02-14 2 views
6

Я разработал много кода на Java и пробовал в Groovy и Haskell, который теперь привел меня к Scala.Scala тестируемый код с наследованием и микшинами

Я чувствую себя относительно комфортно с функциональной стороной Scala, но я нахожу себя немного шатким по объектно-ориентированному дизайну в Scala, потому что он немного отличается от Java, в частности из-за особенностей/микширования.

Я стремлюсь писать код, который, как проверяемый, насколько это возможно, что в моем развитии Java всегда пересчитываются в центр внимания на

  • неизменности где можно
  • Предпочитает инъекцию состояния конструкторов
  • ВСЕГДА идет для состава вместо наследования (сильно зависит от и, возможно, чрезмерной реакции на this post on SO)

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

Программирование Scala (Wampler и Payne, O'Reilly, второе издание) имеет раздел с соображениями («Хороший объектно-ориентированное проектирование: экскурс»), и я прочитал несколько постов на SO, но я не видел явных упоминаний о контроле за тестированием. Книга предлагает этот совет по использованию наследования:

  1. Абстрактный базовый класс или признак подклассы один уровень с помощью конкретных классов, включая тематические классы.
  2. Конкретные классы никогда не подклассы, за исключением двух случаев:
    • классов, которые смешиваются в других видах поведения, определенном в чертах (...)
    • Test-только версии для содействия автоматизированной установки teting.
  3. Когда подклассы кажутся правильными, рассмотрите поведение разбиения на черты и смешайте их в этих чертах.
  4. Никогда не разделяйте логическое состояние между границами типа parent-child.

Некоторые рыть на SO также предполагает, что sometimes mix-ins are preferable to composition.

Таким образом, в сущности, у меня есть два вопроса:

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

  2. Смешивание предлагает хорошие способы повышения тестируемости моего кода?

ответ

8

Использование признаков в Q/A, на которое вы ссылались, действительно касалось гибкости, обеспечиваемой смешиванием признаков.

В примере, когда вы явно расширяете черту, компилятор блокирует типы класса и суперкласс во время компиляции. В этом примере MyService является LockingFlavorA

trait Locking { // ... } 

class LockingFlavorA extends Locking { //... } 

class MyService extends LockingFlavorA { 

} 

Когда вы использовали набранный ссылку собственного (как показано в Q/A вы указали на):

class MyService { 
    this: Locking => 
} 

.. Locking может относиться к самому Locking , или любой действительный подкласс Locking. Затем автор смешивает в запирающей реализации на месте вызова, без явного создания нового класса для этой цели:

val myService: MyService = new MyService with JDK15Locking 

Я думаю, когда они говорят, что вы можете облегчить тестирование, они на самом деле говорят об использовании этой функции для эмулировать то, что мы, разработчики Java, обычно делаем с составом и макетными объектами. Вы просто делаете ложную реализацию Locking и смешиваете ее во время теста и выполняете реальную реализацию во время выполнения.

На ваш вопрос: это лучше или хуже, чем использование насмешливой библиотеки и инъекции зависимостей? Было бы трудно сказать, но я думаю, что в конце концов многие из них пойдут на то, насколько хорошо одна техника или другая игра играет с остальной частью вашей кодовой базы.

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

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

Я думаю, что истинный ответ окажется весьма ситуативным.

TL; DR ниже

Вопрос 1) Я думаю, что это ситуативно полезная альтернатива композиции/DEP-инъекц, но я не думаю, что это дает какие-либо основные выгоды, кроме, возможно, простоты.

Вопрос 2) Да, он может улучшить тестируемость, в основном путем эмуляции имитирующих объектов посредством реализации признаков.

+0

Спасибо. Я очень ценю этот ответ, поскольку он дает хорошие комментарии к моим ссылкам и прямым ответам на вопросы. –

+1

Нет проблем, Scala - интересный язык, и хорошо понимать, как некоторые из этих более эзотерических языковых особенностей соответствуют тем, что люди уже делали там в мире. Это был хороший вопрос. –

+0

хм ... судя по его большому тучному нулевому балу, я полагаю, это могло быть лучше. Но я получил свой ответ, это важная часть. –

3

У меня есть опыт работы с комбинацией микширования и композиции.

поэтому в качестве примера используйте компонент для микширования поведения в определенный признак. В приведенном ниже примере показана структура, использующая несколько признаков уровня dao в классе.

trait ServiceXXX { 
    def findAllByXXX(): Future[SomeClass] 
} 

trait ServiceYYY { 
    def findAllByYYY(): Future[AnotherClass] 
} 

trait SomeTraitsComponent { 
    val serviceXXX: ServiceXXX 
    val serviceYYY: ServiceYYY 
} 

trait SomeTraitsUsingMixing { 
    self: SomeTraitsComponent => 

    def getXXX() = Action.async { 
    serviceXXX.findAllByXXX() map { results => 
     Ok(Json.toJson(results)) 
    } 
    } 

    def getYYY() = Actiona.async { 
    serviceYYY.findAllByYYY() map {results => 
     Ok(Json.toJson(results)) 
    } 
    } 
} 

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

trait ConreteTraitsComponent extends SomeTraitsComponent { 
    val serviceXXX = new ConcreteServiceXXX 
    val serviceYYY = new ConcreteServiceYYY 
} 

object SomeTraitsUsingMixing extends ConreteTraitsComponent 

Используя эту модель йо может легко создать тестовый компонент и использовать макет для проверки конкретного поведения вашего Тейт/класс:

trait SomeTraitsComponentMock { 
    val serviceXXX = mock[ServiceXXX] 
    val serviceYYY = mock[ServiceYYY] 
} 

object SomeTraitsUsingMixingMock extends SomeTraitsComponentMock 

И в вас спецификации вы могли бы объявить контролировать результаты услуг с использованием ScalaMock http://scalamock.org/

+0

Благодарим вас за ответ. Можете ли вы подробнее рассказать о том, почему вы решили сделать «ConcreteTraitsComponent» признаком, а не классом? –

+0

Я предпочитаю объявлять единицу функций как признак как можно дольше, поскольку в scala возможно только [продлить один класс] (http://stackoverflow.com/questions/2005681/difference-between-abstract-class- и-черта), но из нескольких признаков. – toggm

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