This is one of the notes for Dart.

Mixins are method patterns that reuse code from a class in multiple inheritance.

For example, A, B and C are three musicians. A can play piano and guitar, B can play piano and ukulele, and C can play ukulele and guitar. We can define three classes.

class Musician {}abstract class Paino {
    void playPaino();
}

abstract class Guita {
    void playGuita();
}

abstract class Ukelele {
    void playUkelele();
}

class A extends Musician implements Paino.Guita {
    void playPaino() {}
    void playGuita() {}
}

class B extends Musician implements Paino.Ukelele {
    void playPaino() {}
    void playUkelele() {}
}

class C extends Musician implements Ukelele.Guita {
    void playUkelele() {}
    void playGuita() {}
}
Copy the code

That solved our problem, but a new problem arose: we were going to implement the void playPaino(), void playGuita(), and void playUkelele() methods in each class.

This can be too cumbersome, and it’s not DRY.

Is there any other way to extract the same method? That’s where mixin comes in.

Use the mixin keyword to fulfill the above requirements.

class Musician {}mixin GuitaMaster {
    void playGuita() {
        print('guita master'); }}mixin PainoMaster {
    void playPaino() {
        print('paino master'); }}mixin UkeleleMaster {
    void playUkelele() {
        print('ukelele master'); }}mixin PokemonMaster {
    void playPokemonGo() {
        print('pokemon get daze! '); }}class A with GuitaMaster.PainoMaster {}class B with PainoMaster.UkeleleMaster {}class C with UkeleleMaster.GuitaMaster {}Copy the code

Note the difference: In abstract we do not define the implementation logic of the interface, only that the method must be implemented in the implementation class.

In an abstract class, we can implement concrete methods, but when an abstract class is used as an interface, the method must be reimplemented in the class, ignoring the implementation in the abstraction. Abstract classes can be used as parent classes, so when extends subclasses are used, implementations within the abstraction can be implemented.

But in mixins, we define concrete method implementations. This still solves our needs, but is more reusable.

In addition to defining mixins as above, the class itself can be treated as a mixin.

Another important note: Mixins must inherit directly from the Object class, or directly or indirectly from the class after the extends keyword.

You can specify the on keyword to specify which classes can be inherited.

In the following example, this only works if the mixed subclass extends to the Musician class.

class Musician {}class Pokemonor {}mixin GuitaMaster on Musician {
    void playGuita() {
        print('guita master'); }}mixin PainoMaster on Musician {
    void playPaino() {
        print('paino master'); }}mixin UkeleleMaster on Musician {
    void playUkelele() {
        print('ukelele master'); }}mixin PokemonMaster on Pokemonor {
    void playPokemonGo() {
        print('pokemon get daze! '); }}class A extends Musician with GuitaMaster.PainoMaster {}class B extends Musician with PainoMaster.UkeleleMaster {}class C extends Musician with UkeleleMaster.GuitaMaster {}// The following example is an error because it does not inherit from the 'Musician' class
class D extends Pokemonor with UkeleleMaster {}Copy the code