Я очень хорошо знаком с концепциями интерфейсов и абстрактных классов, но не очень хорошо знаком с понятиями mixins.
Прямо сейчас, в Дарте, каждый класс A
определяет неявный интерфейс, который может быть реализован другим классом B
с помощью ключевого слова implements
. Нет явного способа объявления интерфейсов, например, в Java, где интерфейс содержит только нереализованные методы (и в конечном итоге статические переменные). В Dart, поскольку интерфейсы определены классами, методы интерфейса A
могут быть уже реализованы, но класс, реализующий B
все же должен переопределять эти реализации.
Мы можем видеть эту ситуацию из следующего фрагмента кода:
class A {
void m() {
print("method m");
}
}
// LINTER ERROR: Missing concrete implementation of A.m
// Try implementing missing method or make B abstract.
class B implements A {
}
В Dart, mixin также определяется с помощью обычных объявлений класса...
... В принципе, каждый класс определяет mixin, который можно извлечь из него. Однако в этом предложении смесь может быть извлечена только из класса, у которого нет объявленных конструкторов. Это ограничение позволяет избежать осложнений, возникающих из-за необходимости передавать параметры конструктора по цепочке наследования.
Mixin - это в основном класс, который может определять как нереализованные, так и реализованные методы. Это способ добавления методов в другой класс без необходимости логического использования наследования. В Dart mixin применяется к суперклассу, который распространяется через "нормальное" наследование, как в следующем примере:
class A {
void m() {
print("method m");
}
}
class MyMixin {
void f(){
print("method f");
}
}
class B extends A with MyMixin {
}
В этом случае следует отметить, что B
не нужно применять какие-либо дополнительные методы как A
и MyMixin
.
Там существует четкое различие между применением mixin к классу и наследованием от класса, по крайней мере, на языке, который поддерживает только однопользовательское наследование, поскольку в этом случае мы могли бы применять много микшинов к классу, но класс мог бы просто наследуется от другого класса.
Также существует четкое различие между реализацией интерфейса и наследованием от класса. Класс, реализующий интерфейс, должен обязательно выполнять все методы, определенные интерфейсом.
Итак, в целом, концепция реализации интерфейса больше связана с установлением контракта с классом, который реализует интерфейс, а концепция mixins (как следует из названия) - это больше о повторном использовании кода (без повторения иерархии наследования).
Когда использовать mixins и когда использовать интерфейсы в Dart? Существуют ли какие-либо эмпирические правила, по крайней мере, для специальных повторяющихся шаблонов при разработке программного обеспечения, где было бы лучше определить mixin и применить его к суперклассу, вместо того чтобы сделать наш класс реализованным интерфейсом? Я был бы признателен за конкретные примеры проектных решений в контексте, где могут использоваться оба интерфейса и mixins, но один используется по другому (по какой-то причине).