Menu
Coddy logo textTech

Введение в Mixins

Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 50 из 110.

Вы узнали, что Dart позволяет расширять только один класс, и хотя вы можете реализовывать несколько интерфейсов, вам придется писать весь код самостоятельно. Но что, если вы хотите разделить фактический код реализации между несколькими несвязанными классами? Именно здесь на помощь приходят миксины (mixins).

Примесь (mixin) — это способ повторного использования кода в нескольких иерархиях классов. Представьте это как набор методов и свойств, которые можно «подмешать» в любой класс, наделяя его новыми возможностями без использования наследования.

mixin Swimming {
  void swim() {
    print('Swimming through the water');
  }
}

class Duck with Swimming {
  void quack() {
    print('Quack!');
  }
}

class Fish with Swimming {
  void blowBubbles() {
    print('Blub blub');
  }
}

void main() {
  var duck = Duck();
  duck.quack();
  duck.swim();  // Из примеси (mixin)
  
  var fish = Fish();
  fish.swim();  // Та же реализация, другой класс
}

Обратите внимание на ключевое слово with — именно так вы применяете миксин к классу. В отличие от implements, вам не нужно писать метод самостоятельно. Миксин предоставляет сам код, и ваш класс автоматически получает эту функциональность.

Примеси решают реальную проблему: Duck и Fish не связаны через наследование, но им обоим требуется поведение плавания. С помощью примесей вы пишете код один раз и используете его везде, где это необходимо.

challenge icon

Задание

Легко

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

Вы организуете свой код в два файла:

  • instruments.dart: Определите здесь свой миксин и классы инструментов:
    • Миксин Tunable с методом tune(), который выводит Tuning the instrument..., и методом checkTuning(), который выводит Tuning is perfect!
    • Класс Guitar, использующий миксин Tunable. Добавьте свойство String brand с конструктором. Включите метод strum(), который выводит [brand] guitar strumming chords
    • Класс Piano, который также использует миксин Tunable. Добавьте свойство int keys с конструктором. Включите метод play(), который выводит Playing [keys]-key piano
  • main.dart: Импортируйте файл с инструментами и продемонстрируйте, как оба несвязанных инструмента получают возможности настройки из одного и того же миксина:
    • Создайте Guitar с брендом 'Fender'
    • Создайте Piano с 88 клавишами
    • Для гитары: вызовите tune(), затем strum(), затем checkTuning()
    • Выведите пустую строку
    • Для пианино: вызовите tune(), затем play(), затем checkTuning()

Обратите внимание, что Guitar и Piano — это совершенно разные инструменты без иерархии наследования, однако они оба получают одни и те же методы настройки из миксина Tunable. Вы пишете код настройки один раз, и оба класса могут использовать его с помощью ключевого слова with.

Ожидаемый вывод:

Tuning the instrument...
Fender guitar strumming chords
Tuning is perfect!

Tuning the instrument...
Playing 88-key piano
Tuning is perfect!

Шпаргалка

Миксин (mixin) — это способ повторного использования кода в нескольких несвязанных классах без использования наследования. Это набор методов и свойств, которые вы можете «подмешать» в любой класс.

Определите миксин с помощью ключевого слова mixin:

mixin Swimming {
  void swim() {
    print('Swimming through the water');
  }
}

Примените миксин к классу с помощью ключевого слова with:

class Duck with Swimming {
  void quack() {
    print('Quack!');
  }
}

class Fish with Swimming {
  void blowBubbles() {
    print('Blub blub');
  }
}

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

Теперь и Duck, и Fish могут использовать метод swim(), хотя они не связаны через наследование:

var duck = Duck();
duck.swim();  // Из миксина

var fish = Fish();
fish.swim();  // Та же реализация, другой класс

Попробуйте сами

import 'instruments.dart';

void main() {
  // TODO: Создайте Guitar с брендом 'Fender'
  
  // TODO: Создайте Piano с 88 клавишами
  
  // TODO: Для гитары: вызовите tune(), затем strum(), затем checkTuning()
  
  // TODO: Выведите пустую строку
  
  // TODO: Для пианино: вызовите tune(), затем play(), затем checkTuning()
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование