@@ -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,29 +61,104 @@ 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
+ By declaring the mixin as abstract, you force any type that uses
76
+ it to define the abstract method upon which its behavior depends.
77
+
78
+ ``` dart
79
+ abstract 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
+ ?
127
+ ```
128
+
129
+ ### Use the ` on ` clause to declare a superclass
130
+
131
+ The ` on ` clause exists to define the type that ` super ` calls are resolved against.
132
+ So, you should only use it if you need to have a ` super ` call inside a mixin.
133
+
134
+ The ` on ` clause forces any class that uses a mixin to also be a subclass
135
+ of the type in the ` on ` clause.
136
+ If the mixin depends on members in the superclass,
137
+ this ensures those members are available where the mixin is used:
68
138
69
139
<? code-excerpt "misc/lib/language_tour/classes/orchestra.dart (mixin-on)" plaster="none" replace="/on Musician2/[!on Musician!]/g" ?>
70
140
``` dart
71
141
class Musician {
72
- // ...
142
+ musicianMethod() {
143
+ print('Playing music!');
144
+ }
73
145
}
74
146
mixin MusicalPerformer [!on Musician!] {
75
- // ...
147
+ perfomerMethod() {
148
+ print('Performing music!');
149
+ super.musicianMethod();
150
+ }
76
151
}
77
- class SingerDancer extends Musician with MusicalPerformer {
78
- // ...
152
+
153
+ class SingerDancer extends Musician with MusicalPerformer { }
154
+
155
+ main() {
156
+ SingerDance().performerMethod();
79
157
}
80
158
```
81
159
82
- In the preceding code,
83
- only classes that extend or implement the ` Musician ` class
84
- can use the mixin ` MusicalPerformer ` .
85
- Because ` SingerDancer ` extends ` Musician ` ,
160
+ In this example, only classes that extend or implement the ` Musician ` class
161
+ can use the mixin ` MusicalPerformer ` . Because ` SingerDancer ` extends ` Musician ` ,
86
162
` SingerDancer ` can mix in ` MusicalPerformer ` .
87
163
88
164
## ` class ` , ` mixin ` , or ` mixin class ` ?
@@ -95,49 +171,24 @@ A `mixin` declaration defines a mixin. A `class` declaration defines a [class][]
95
171
A ` mixin class ` declaration defines a class that is usable as both a regular class
96
172
and a mixin, with the same name and the same type.
97
173
98
- Any restrictions that apply to classes or mixins also apply to mixin classes:
99
-
100
- - Mixins can't have ` extends ` or ` with ` clauses, so neither can a ` mixin class ` .
101
- - Classes can't have an ` on ` clause, so neither can a ` mixin class ` .
102
-
103
- ### ` abstract mixin class `
104
-
105
- You can achieve similar behavior to the ` on ` directive for a mixin class.
106
- Make the mixin class ` abstract ` and define the abstract methods its behavior
107
- depends on:
108
-
109
174
``` dart
110
- abstract mixin class Musician {
111
- // No 'on' clause, but an abstract method that other types must define if
112
- // they want to use (mix in or extend) Musician:
113
- void playInstrument(String instrumentName);
114
-
115
- void playPiano() {
116
- playInstrument('Piano');
117
- }
118
- void playFlute() {
119
- playInstrument('Flute');
120
- }
175
+ mixin class Musician {
176
+ // ...
121
177
}
122
178
123
- class Virtuoso with Musician { // Use Musician as a mixin
124
- void playInstrument(String instrumentName) {
125
- print('Plays the $instrumentName beautifully');
126
- }
127
- }
179
+ class Novice with Musician { // Use Musician as a mixin
180
+ // ...
181
+ }
128
182
129
183
class Novice extends Musician { // Use Musician as a class
130
- void playInstrument(String instrumentName) {
131
- print('Plays the $instrumentName poorly');
132
- }
133
- }
184
+ // ...
185
+ }
134
186
```
135
187
136
- By declaring the ` Musician ` mixin as abstract, you force any type that uses
137
- it to define the abstract method upon which its behavior depends.
188
+ Any restrictions that apply to classes or mixins also apply to mixin classes:
138
189
139
- This is similar to how the ` on ` directive ensures a mixin has access to any
140
- interfaces it depends on by specifying the superclass of that interface .
190
+ - Mixins can't have ` extends ` or ` with ` clauses, so neither can a ` mixin class ` .
191
+ - Classes can't have an ` on ` clause, so neither can a ` mixin class ` .
141
192
142
193
[ language version ] : /guides/language/evolution#language-versioning
143
194
[ class ] : /language/classes
0 commit comments