On occasion, the usual subclass and interface approach to classes is not quite right. One such case occurs so often that Dart supports it directly in the language: mixins. The purpose of mixins is to augment subclassing with additional behavior. This additional behavior is typically something that we will want to reuse in other classes as well.
Consider two simple classes, Person and Animal:
classes/mixins.dart | |
| class Person { |
| String name; |
| Person(this.name); |
| } |
| |
| class Animal { |
| String name; |
| Animal(this.name); |
| } |
These two classes are unrelated to each other, though they do share a common name property.
During the course of working with these classes, we decide that we need subclasses of both. The Friend class will extend Person to represent a person with a more intimate relationship. Similarly, the Pet class will extend Animal to encapsulate an animal to which a person might have a special bond.
In both cases, the intimate nature of an implied relationship suggests that we want to be able to warmly greet a Friend or Pet. The greeting will be identical except for the name (“Howdy Alice!” “Howdy Snoopy!”). So the question becomes how do we add this common functionality without duplicating code?
The answer, of course, is with mixins. A mixin is declared as an abstract class. The class is abstract because the class into which it gets mixed will supply some vital information or behavior. In the case of our friends and pets, the corresponding classes will supply the name.
| abstract class Greeting { |
| String get name; |
| greet() => "Howdy $name!"; |
| } |
Our greet method is fully defined, but the name getter method is left abstract by virtue of being declared without a method body. Both Person and Animal already define this getter by way of a name instance variable. In other words, Greeting is ready to mix in with both classes.
The syntax for mixins works with the extends keyword. In Dart, we say that a class extends another with a mixin. So Friend extends Person with Greeting. Pet extends Animal with the same Greeting mixin.
| class Friend extends Person with Greeting { |
| Friend(name): super(name); |
| } |
| |
| class Pet extends Animal with Greeting { |
| Pet(name): super(name); |
| } |
That’s all there is to it. Both the Friend and Pet classes now have Greeting’s greet method available for use:
| var say_hi = new Friend('Alice').greet(); |
| // => 'Howdy Alice!' |
| var say_hi = new Pet('Snoopy').greet(); |
| // => 'Howdy Snoopy!' |
Dart expects mixins to work with subclasses. It is possible to mix in traits to top-level classes. In such cases, we would have to extend Object with the mixin. If that seems a little awkward, this is Dart’s way of telling us that we might be better off using a subclass in such cases.
18.191.68.18