Каковы преимущества подхода к торту при расширении старомодной черты?

Я пытаюсь выяснить, в чем разница между смешиванием черт с помощью паттерна Cake и смешиванием их с помощью старомодного расширения. Вот два моих примера:

Через расширение

trait X {
  def foo()
}

trait Y extends X {
  def bar()
}

class Z extends Y {
  def foo() = ()
  def bar() = ()
}

И через торт

trait N {
  def foo()
}

trait M {
  this: N =>
  def bar()
}

class U extends M with N {
  def bar() = ()
  def foo() = ()
}

Каковы преимущества подхода торт? Они оба одинаковы для меня. Может быть, я ошибаюсь, но я не вижу существенной разницы.

1 ответ

Решение

Если я хочу обогатить функциональность XПервый подход:

// I am X
// I give you everything X provides
trait Y extends X {
  def bar()
}

Если я хочу использовать функциональность NЯ бы использовал второй подход:

// I am an extension of N
// I require you to be N
trait M { this: N =>
  def bar()
}

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

Черты, формирующие class U реализовано в вашем примере, чтобы получить разрешение справа налево. Наличие вменяемого Порядка разрешения методов (MRO) дает нам свободу смешивать любые черты "наращиваемым способом".

Другие вопросы по тегам