はじめに
Dartでクラスを設計していると、
extends / with / implements の3つがよく登場します。
特に with と implements は一見似ていますが、目的も使い方もまったく異なります。
この記事では、実例と図解でわかりやすく整理していきます💡
1. with:Mixin(ミックスイン)を使う
with は クラスに特定の機能(メソッドや変数)を混ぜ込むために使います。
「継承」ではなく「合成」です。
mixin(ミックスイン)= 機能を他のクラスに再利用できる仕組み
例:ログ出力機能をミックスインする
mixin Logger {
void log(String message) {
print('[LOG] $message');
}
}
class Service with Logger {
void run() {
log('Service started');
}
}
void main() {
final s = Service();
s.run(); // => [LOG] Service started
}
Service クラスは Logger のメソッドをそのまま利用できます。
親クラスがなくても機能を“注入”できるのがポイントです。
複数の mixin も合成可能
mixin Cacheable {
void cache() => print('Saved to cache');
}
mixin Networkable {
void fetch() => print('Fetched from API');
}
class DataManager with Cacheable, Networkable {}
void main() {
final dm = DataManager();
dm.fetch();
dm.cache();
}
→ with では複数の mixin を自由に組み合わせ可能です(多重継承のような柔軟さ)。
2. implements:インターフェースを実装する
implements は、別のクラスや抽象クラスのインターフェース(契約)を実装するときに使います。
定義だけ借りて、自分で中身を書く必要があります。
例:インターフェースを実装する
abstract class Printable {
void printMessage();
}
class Report implements Printable {
@override
void printMessage() {
print('Report content');
}
}
implements では、元クラスの中身(処理)は引き継がれません。
すべて自分で定義し直す必要があります。
複数のインターフェースを同時に実装できる
abstract class A {
void foo();
}
abstract class B {
void bar();
}
class C implements A, B {
@override
void foo() => print('foo');
@override
void bar() => print('bar');
}
→ インターフェース実装(implements)は多重実装が可能です。
3. extends / with / implements の比較表
| キーワード | 継承対象 | 実装を引き継ぐ | メソッドの中身 | 複数指定 | 主な用途 |
|---|---|---|---|---|---|
| extends | クラス | ✅ 引き継ぐ | 再利用できる | ❌ | 親クラスの機能を拡張 |
| with | mixin | ✅ 引き継ぐ | そのまま使える | ✅ | 共通処理の合成 |
| implements | 抽象/具象クラス | ❌ 引き継がない | 自分で実装 | ✅ | インターフェース契約 |
4. 3つを組み合わせた実践例
Flutter開発では、これらを同時に使うケースも多いです。
たとえば以下のようなクラス定義
mixin Flyable {
void fly() => print('Flying!');
}
abstract class Animal {
void eat();
}
class Bird extends Animal with Flyable implements Comparable<Bird> {
@override
void eat() => print('Pecking grains');
@override
int compareTo(Bird other) => 0;
}
void main() {
var bird = Bird();
bird.eat(); // Pecking grains
bird.fly(); // Flying!
}
解説
| 構文 | 意味 |
|---|---|
extends Animal |
「動物」という基本的性質を継承 |
with Flyable |
飛ぶ機能を合成(Mixin) |
implements Comparable |
並び替え可能な「契約」を実装 |
5. Flutterでの実例:TickerProviderStateMixin
Flutterの State クラスでも実際に with が使われています。
class _MyWidgetState extends State<MyWidget> with TickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this);
}
}
TickerProviderStateMixin は、アニメーション制御に必要な Ticker を提供する mixin です。
これを with で合成することで、State クラスがアニメーションに対応できるようになります。
まとめ
| 用語 | 概要 |
|---|---|
extends |
親クラスを継承して機能を拡張 |
with |
mixin(機能モジュール)をクラスに合成 |
implements |
インターフェースを契約的に実装(中身は自作) |
Dartでは「多重継承ができない」代わりに、
with(mixin)と implements(インターフェース実装)を使い分けることで、
柔軟で保守性の高い設計が可能になります。