Summary: in this tutorial, you’ll learn about Dart mixin and how to use mixins to reuse code in multiple hierarchies.
Introduction to the Dart mixins
Let’s start with an example.
First, define an abstract class called Model
that is the base class of all model classes:
abstract class Model {
}
Code language: Dart (dart)
Second, define three classes User
, Post
, and Comment
that inherit from the Model
class:
class User extends Model {}
class Post extends Model {}
class Comment extends Model {}
Code language: Dart (dart)
Suppose you want to implement a shareable function for the Post
and Comment
classes but not for the User
class. To do that, you’ll have a number of options.
1) Add the share() method to the Model class
In this option, we add the share()
method to the Model
class. Because the User
class is a subclass of the Model
class, it becomes shareable, which is not correct:
abstract class Model {
void share(String content) {
print('Share the $content');
}
}
Code language: Dart (dart)
Also, all the future classes that inherit from the Model
class will be able to access the share()
method which may not what you expected.
To work around this, you may override the share()
method and raise an exception in the subclasses that you don’t want to be shareable. For example:
class User extends Model {
@override
void share(String content) {
throw UnimplementedError();
}
}
Code language: Dart (dart)
However, this option is not ideal.
2) Creating a new base class for shareable classes
In this option, first, define a Shareable
class that extends the Model
class and add the share()
method to the Shareable
class:
abstract class ShareableModel extends Model {
void share(String content) {
print('Share the $content');
}
}
Code language: Dart (dart)
Second, extend the ShareableModel
class from the Post
and Comment
classes:
class Post extends ShareableModel {}
class Comment extends ShareableModel {}
Code language: Dart (dart)
This solution works fine for this class hierarchy.
However, if a class that is in another class hierarchy wants to reuse the share()
method, it’s not possible.
3) Creating a new interface
In this option, first, define a Shareable
interface and implement it from the Post
and Comment
classes:
abstract class Shareable {
void share(String $content);
}
class Post extends Model implements Shareable {
void share(String content) {
print('Share the $content');
}
}
class Comment extends Model implements Shareable {
void share(String content) {
print('Share the $content');
}
}
Code language: Dart (dart)
However, this option causes duplicate code in the Post
and Comment
class.
Dart mixin to the rescue
All the three options have pros and cons and none of them is ideal. To resolve this, Dart comes up with the mixin concept.
Mixins allow you to share behaviors between one or more classes without using inheritance.
A mixin is like a class. To define a mixin, you use the mixin
keyword instead of the class
keyword. Inside the mixin, you define the methods.
For example, the following defines the Shareable
mixin:
mixin Shareable {
void share(String content) {
print('Share the $content');
}
}
Code language: Dart (dart)
Unlike a class, a mixin doesn’t have a constructor and it cannot be instantiated. For example, the following causes an error because it attempts to create an object from a mixin:
var share = Shareable(); // ERROR
Code language: Dart (dart)
Also, you cannot inherit from a mixin. For example, the following attempts to extend a mixin. It results in an error:
// ERROR
class MyShareable extends Shareable {}
Code language: Dart (dart)
To use a mixin in other classes, you use the with
keyword.
For example, the following Post
and Comment
classes extend the Model
class and use the Shareable
mixin:
class Post extends Model with Shareable {}
class Comment extends Model with Shareable {}
Code language: Dart (dart)
Once a class uses a mixin, its objects can access all the methods of the mixin. For example:
var post = Post();
post.share('The first post.');
var comment = Comment();
comment.share('My first comment.');
Code language: Dart (dart)
If you want to use the Shareable
mixin in a class, you use the with
keyword. For example, the following defines the Video
class that is not in the current class hierarchy and uses the Shareable
mixin:
class Video with Shareable {}
Code language: Dart (dart)
Put it all together.
abstract class Model {}
class User extends Model {}
mixin Shareable {
void share(String content) {
print('Share the $content');
}
}
class Post extends Model with Shareable {}
class Comment extends Model with Shareable {}
class Video with Shareable {}
void main() {
var post = Post();
post.share('The first post.');
var comment = Comment();
comment.share('My first comment.');
var video = Video();
video.share('Share the video');
}
Code language: Dart (dart)
Summary
- Use mixins to share behaviors between one or more classes.
- Use the
mixin
keyword to define a mixin. Unlike a class, a mixin cannot be instantiated and it cannot have a constructor. - Use the
with
keyword to use a mixin in a class.