Каковы преимущества подхода к торту при расширении старомодной черты?
Я пытаюсь выяснить, в чем разница между смешиванием черт с помощью паттерна 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) дает нам свободу смешивать любые черты "наращиваемым способом".