@@ -16,7 +16,8 @@ Mixins are a way of defining code that can be reused in multiple class hierarchi
16
16
They are intended to provide member implementations en masse.
17
17
18
18
To use a mixin, use the ` with ` keyword followed by one or more mixin
19
- names. The following example shows two classes that use mixins:
19
+ names. The following example shows two classes that use (or, are subclasses of)
20
+ mixins:
20
21
21
22
<? code-excerpt "misc/lib/language_tour/classes/orchestra.dart (musician-and-maestro)" replace="/(with.*) \{/[!$1!] {/g"?>
22
23
``` dart
@@ -60,30 +61,120 @@ mixin Musical {
60
61
}
61
62
```
62
63
63
- Sometimes you might want to restrict the types that can use a mixin.
64
- For example, the mixin might depend on being able to invoke a method
65
- that the mixin doesn't define.
66
- As the following example shows, you can restrict a mixin's use
67
- by using the ` on ` keyword to specify the required superclass:
64
+ ## Specify members a mixin can call on itself
65
+
66
+ Sometimes a mixin depends on being able to invoke a method or access fields,
67
+ but can't define those members itself (because mixins can't use constructor
68
+ parameters to instantiate their own fields).
69
+
70
+ The following sections cover different strategies for ensuring any subclass
71
+ of a mixin defines any members the mixin's behavior depends on.
72
+
73
+ ### Define abstract members in the mixin
74
+
75
+ Declaring an abstract method in a mixin forces any type that uses
76
+ the mixin to define the abstract method upon which its behavior depends.
77
+
78
+ ``` dart
79
+ mixin Musician {
80
+ void playInstrument(String instrumentName); // Abstract method.
81
+
82
+ void playPiano() {
83
+ playInstrument('Piano');
84
+ }
85
+ void playFlute() {
86
+ playInstrument('Flute');
87
+ }
88
+ }
89
+
90
+ class Virtuoso with Musician {
91
+ void playInstrument(String instrumentName) { // Subclass must define.
92
+ print('Plays the $instrumentName beautifully');
93
+ }
94
+ }
95
+ ```
96
+
97
+ #### Access state in the mixin's subclass
98
+
99
+ Declaring abstract memebers also allows you to access state on the subclass
100
+ of a mixin, by calling getters which are defined as abstract on the mixin:
101
+
102
+ ``` dart
103
+ /// Can be applied to any type with a [name] property and provides an
104
+ /// implementation of [hashCode] and operator `==` in terms of it.
105
+ mixin NameIdentity {
106
+ String get name;
107
+
108
+ int get hashCode => name.hashCode;
109
+ bool operator ==(other) => other is NameIdentity && name == other.name;
110
+ }
111
+
112
+ class Person with NameIdentity {
113
+ final String name;
114
+
115
+ Person(this.name);
116
+ }
117
+ ```
118
+
119
+ ### Implement an interface
120
+
121
+ Similar to declaring the mixin abstract, putting an ` implements ` clause on the
122
+ mixin while not actually implementing the interface will also ensure any member
123
+ dependencies are defined for the mixin.
124
+
125
+ ``` dart
126
+ abstract interface class Tuner {
127
+ void tuneInstrument();
128
+ }
129
+
130
+ mixin Guitarist implements Tuner {
131
+ void playSong() {
132
+ tuneInstrument();
133
+
134
+ print('Strums guitar majestically.');
135
+ }
136
+ }
137
+
138
+ class PunkRocker with Guitarist {
139
+ void tuneInstrument() {
140
+ print("Don't bother, being out of tune is punk rock.");
141
+ }
142
+ }
143
+ ```
144
+
145
+ ### Use the ` on ` clause to declare a superclass
146
+
147
+ The ` on ` clause exists to define the type that ` super ` calls are resolved against.
148
+ So, you should only use it if you need to have a ` super ` call inside a mixin.
149
+
150
+ The ` on ` clause forces any class that uses a mixin to also be a subclass
151
+ of the type in the ` on ` clause.
152
+ If the mixin depends on members in the superclass,
153
+ this ensures those members are available where the mixin is used:
68
154
69
- <? code-excerpt "misc/lib/language_tour/classes/orchestra.dart (mixin-on)" plaster="none" replace="/on Musician2/[!on Musician!]/g"?>
70
155
``` dart
71
156
class Musician {
72
- // ...
157
+ musicianMethod() {
158
+ print('Playing music!');
159
+ }
73
160
}
74
161
75
162
mixin MusicalPerformer [!on Musician!] {
76
- // ...
163
+ perfomerMethod() {
164
+ print('Performing music!');
165
+ super.musicianMethod();
166
+ }
77
167
}
78
- class SingerDancer extends Musician with MusicalPerformer {
79
- // ...
168
+
169
+ class SingerDancer extends Musician with MusicalPerformer { }
170
+
171
+ main() {
172
+ SingerDance().performerMethod();
80
173
}
81
174
```
82
175
83
- In the preceding code,
84
- only classes that extend or implement the ` Musician ` class
85
- can use the mixin ` MusicalPerformer ` .
86
- Because ` SingerDancer ` extends ` Musician ` ,
176
+ In this example, only classes that extend or implement the ` Musician ` class
177
+ can use the mixin ` MusicalPerformer ` . Because ` SingerDancer ` extends ` Musician ` ,
87
178
` SingerDancer ` can mix in ` MusicalPerformer ` .
88
179
89
180
## ` class ` , ` mixin ` , or ` mixin class ` ?
@@ -96,49 +187,24 @@ A `mixin` declaration defines a mixin. A `class` declaration defines a [class][]
96
187
A ` mixin class ` declaration defines a class that is usable as both a regular class
97
188
and a mixin, with the same name and the same type.
98
189
99
- Any restrictions that apply to classes or mixins also apply to mixin classes:
100
-
101
- - Mixins can't have ` extends ` or ` with ` clauses, so neither can a ` mixin class ` .
102
- - Classes can't have an ` on ` clause, so neither can a ` mixin class ` .
103
-
104
- ### ` abstract mixin class `
105
-
106
- You can achieve similar behavior to the ` on ` directive for a mixin class.
107
- Make the mixin class ` abstract ` and define the abstract methods its behavior
108
- depends on:
109
-
110
190
``` dart
111
- abstract mixin class Musician {
112
- // No 'on' clause, but an abstract method that other types must define if
113
- // they want to use (mix in or extend) Musician:
114
- void playInstrument(String instrumentName);
115
-
116
- void playPiano() {
117
- playInstrument('Piano');
118
- }
119
- void playFlute() {
120
- playInstrument('Flute');
121
- }
191
+ mixin class Musician {
192
+ // ...
122
193
}
123
194
124
- class Virtuoso with Musician { // Use Musician as a mixin
125
- void playInstrument(String instrumentName) {
126
- print('Plays the $instrumentName beautifully');
127
- }
128
- }
195
+ class Novice with Musician { // Use Musician as a mixin
196
+ // ...
197
+ }
129
198
130
199
class Novice extends Musician { // Use Musician as a class
131
- void playInstrument(String instrumentName) {
132
- print('Plays the $instrumentName poorly');
133
- }
134
- }
200
+ // ...
201
+ }
135
202
```
136
203
137
- By declaring the ` Musician ` mixin as abstract, you force any type that uses
138
- it to define the abstract method upon which its behavior depends.
204
+ Any restrictions that apply to classes or mixins also apply to mixin classes:
139
205
140
- This is similar to how the ` on ` directive ensures a mixin has access to any
141
- interfaces it depends on by specifying the superclass of that interface .
206
+ - Mixins can't have ` extends ` or ` with ` clauses, so neither can a ` mixin class ` .
207
+ - Classes can't have an ` on ` clause, so neither can a ` mixin class ` .
142
208
143
209
[ language version ] : /guides/language/evolution#language-versioning
144
210
[ class ] : /language/classes
0 commit comments